- Continuation 객체는 중단이 되었을 때의 상태와 함수의 지역변수와 파라미터, 그리고 중단 함수를 호출한 함수가 재개될 위치 정보를 가지고 있다. 하나의 컨티뉴에이션 객체가 다른 하나를 참조하고, 참조된 객체가 또 다른 컨티뉴에이션 객체를 참조한다.
- 중단함수는 실행도중 중단될 경우 COROUTINE_SUSPENDED 라는 마커를 반환한다
- 상태는 컨티뉴에이션 객체에 저장되며, 중단을 처리하기 위한 과정이 있어야 한다. 중단된 함수가 재개했을 때 컨티뉴에이션 객체로부터 상태를 복원하고, 얻을 결과를 사용하거나 예외를 던진다.
Continutation 의 구성 예시
suspend fun myFunction() {
println("Before")
var counter = 0
delay(1000)
counter++
println("Counter: $counter")
println("After")
}
// decompile 한 코드를 코틀린으로 작성했을 때
fun myFunction(continuation: Continuation<Unit>): Any {
val continuation = continuation as? MyFunctionContinuation
?: MyFunctionContinuation(continuation)
var counter = continuation.counter
if (continuation.label == 0) {
println("Before")
counter = 0
continuation.counter = counter
continuation.label = 1
if (delay(1000, continuation) == COROUTINE_SUSPENDED) {
return COROUTINE_SUSPENDED
}
}
if (continuation.label == 0) {
counter = (counter as Int) + 1
println("Counter: $counter")
println("After")
return Unit
}
error("Impossible")
}
class MyFunctionContinuation(
val completion: Continuation<Unit>
) : Continuation<Unit> {
override val context: CoroutineContext
get() = completion.context
var result: Result<Unit>? = null
var label = 0
var counter = 0 // 중단 전 저장되어 재개 후 사용할 값
override fun resumeWith(result: Result<Unit>) {
this.result = result
val res = try {
val r = myFunction(this)
if (r == COROUTINE_SUSPENDED) return
Result.success(r as Unit)
} catch (e: Throwable) {
Result.failure(e)
}
completion.resumeWith(res)
}
}
label : 현재 상태를 저장하기 위한 필드
처음 시작될 때 0, 중단되기 전 다음 상태로 설정되어 코루틴이 재개될 시점을 알려줌
result : 함수가 어떻게 재개되었는지를 나타내는 필드
중단 전 저장되어 재개 후 사용되며, 함수가 값으로 재개되었다면 Result.Success(value)를 반환하고 재개함수 내부에서 value 값을 사용할 수 있다. 함수가 예외로 재개되었다면 결과는 Result.Failure(exception)이 되며, 예외를 던진다
'Kotlin' 카테고리의 다른 글
== 과 ===의 차이 (0) | 2023.04.18 |
---|---|
Inner class 와 Nested Class 차이 (0) | 2023.04.18 |
Flow 결합 연산자 : zip, combine (0) | 2023.04.11 |
operator fun invoke (0) | 2023.04.10 |
정렬 (0) | 2023.01.09 |