第07回Kotlin勉強会@Sansanでの発表資料です。
suspending functionの裏側2017/11/9第7回Kotlin勉強会@Sansan@kkagurazaka
View Slide
皆さん、coroutines使ってますか?
KotlinConf Keynote Recap
coroutinesじゃんじゃん使っていきましょう
そんなcoroutinesがどうやって実現されているかその裏側をお話します
自己紹介● Keita Kagurazaka● Android App Developer● Sansan株式会社 2017/4〜● Kotlin / CQRS / DDD /Splatoon / Github: @k-kagurazakaTwitter: @kkagurazaka
coroutinesとは● 中断・再開可能な計算のインスタンス○ Threadクラスのように、作成して実行するlaunch(UI) {val token = fetchToken() // Tokenが取得できるまで実行を中断val item = postItem(token, newItem) // 投稿が完了するまで実行を中断updateUI(item)}
どのように中断・再開を実現しているのか?
suspending function
suspending function● 呼び出されるとcoroutinesを中断する(こともできる)● suspending functionはcoroutinesかsuspending functionからしか呼び出せない● Java byte codeになる際にCPS transformされる
Continuation Passing Style (CPS)戻り値で値を返すのではなく、引数のContinuationインスタンスに結果を渡すことで値を伝達するスタイルinterface Continuation {// 成功したことと、その結果を伝達fun resume(value: T): Unit//失敗したことと、原因の例外を伝達fun resumeWithException(exception: Throwable): Unit}
CPS transform// Kotlinでの宣言suspend fun fetchToken(): Token// 変換後のJava byte codeをKotlinっぽく書いたものfun fetchToken(continuation: Continuation): Any?● 中断する場合は COROUTINE_SUSPENDED 定数を返し、再開するときにContinuationをresumeする● 中断しない場合は結果の T を返す
CPS transform後のイメージlaunch(UI) {fetchToken(object : Continuation {override fun resume(value: Token) {postItem(value, newItem, object: Continuation {override fun resume(value: Item) {updateUI(value)}})}})}suspending functionの呼び出し以降がContinuationを介したコールバックに変換される
内部的な実装とはいえコールバックのネストが深すぎないか?
ステートマシンによる実装class StateMachine implements Continuation {int label = 0; // ステートマシンの状態Token token; // suspending functionのローカル変数Item item; // 同上void resume(Object data) { … }}
void resume(Object data) {switch(label) {case 0:label = 1;data = fetchToken(this); // CPS変換後なのでContinuation=thisを渡すif (data == COROUTINE_SUSPENDED) break; // 中断が発生した場合は抜けるcase 1:token = (Token)data;label = 2;data = postItem(token, newItem, this);if (data == COROUTINE_SUSPENDED) break;case 2:item = (Item)data;updateUI(item)label = -1; // ステートマシンの終了break;}}
内部実装がコールバックヘルというわけではない!
まとめ● coroutineの中断はsuspending functionで発生する● suspending functionはCPS transformによってコールバックに変換される● 複数のsuspending functionの呼び出しはステートマシンにコンパイルされる
Thanks!