-
돼욍 Comment
Coroutine 이 StateMachine 형태로 동작함을 rough 하게 이해할 수 있다.
StateMachine 의 상태 변화에 따라 값을 save & fetch 한다는 것을 rough 하게 이해할 수 있다.
Continuation 이라는 것을 재활용해 Dispatcher 를 포함한 context 를 계속 물고 갈 수 있음을 rough 하게 이해할 수 있다.
-
Kotlin 의 Coroutine 은 suspend 키워드로 마킹된 함수를 CPS(Continuation Passing Style)로 변환하고, 이를 Coroutine Builder 를 통해 적절한 스레드 상에서 시나리오에 따라 동작하도록 구성된다.
-
suspend function 은 스레드와 스케줄의 관리를 수행하는 것이 아니라 비동기 실행을 위한 중단(suspension) 지점의 정의이다.
코루틴은 중단 지점까지 비선점형으로(cooperative) 동작하기 때문에 실행 스케줄이 OS 에 의해 온전히 제어되는 스레드(preemptive)와는 다른 관점에서 보아야 한다.
-
일반적인 subroutine 은 단일 지점에서 시작해서 특정 지점에서 종료한다.
coroutine 은 단일 지점에서 시작, 임의 지점에서 멈춤, 해당 지점에서 재개, 특정 지점에서 종료 가능하다.
-
Kotlin 에서는 sequencial code 를 통해 non-blocking 코드를 작성하기 위한 수단으로 coroutine 제공
-
상태를 저장함으로써 특정 지점에서 다시 시작할 수 있다. (callback 의 개념과 비슷하긴 하다.)
이 상태저장을 Continuation Passing Style (CPS) 라고 한다.
-
public interface Continuation<in T>{ val context:CoroutineContext // 어떤 스레드에서 수행할 것인가? fun resume(value:T) fun resumeWithException(exception:Throwable) }
-
suspend fun fetchUserDetail(id:String){ val token = auth() val user = getUser(token, id) updateUserData(user) }
위 코드가 아래와 같은 느낌으로 state 를 저장한다고 볼 수 있음
fun fetchUserDetail(id:String, cont:Continuation){ // state machine val sm = cont as? thisSM ?: object: CoroutineImpl{ // continuation reuse fun resume(…){ fetchUserDetail(null, this) // resume callback } } swith(sm.label){ case 0: sm.id = id sm.label = 1 // labeling auth(sm) case 1: val id = sm.id val token = sm.result as String sm.label = 2 // labeling getUser(token, id, sm) case 2: ... } }
-
CPS(Continuation Passing Style) transform
StateMachine 에 의해 코드의 실행 위치 처리
함수에 대한 진입/진출 시 상태를 저장/복원하기 위한 코드
Continuation reuse
-
class DispatchedContinuation<in T>(val dispatcher:CoroutineDispatcher, val continuation:Continuation<T>): Continuation<T> by continuation{ override fun resume(value:T){ dispatcher.dispatch(context, DispatchTask(…)) } }
-
끝!!!
댓글