Upgrade to Pro — share decks privately, control downloads, hide ads and more …

suspending functionの裏側

suspending functionの裏側

第07回Kotlin勉強会@Sansanでの発表資料です。

Keita Kagurazaka

November 09, 2017
Tweet

More Decks by Keita Kagurazaka

Other Decks in Programming

Transcript

  1. suspending functionの裏側
    2017/11/9
    第7回Kotlin勉強会@Sansan
    @kkagurazaka

    View Slide

  2. 皆さん、coroutines使ってますか?

    View Slide

  3. KotlinConf Keynote Recap

    View Slide

  4. KotlinConf Keynote Recap

    View Slide

  5. View Slide

  6. coroutines
    じゃんじゃん使っていきましょう

    View Slide

  7. そんなcoroutinesが
    どうやって実現されているか
    その裏側をお話します

    View Slide

  8. 自己紹介
    ● Keita Kagurazaka
    ● Android App Developer
    ● Sansan株式会社 2017/4〜
    ● Kotlin / CQRS / DDD /
    Splatoon / Github: @k-kagurazaka
    Twitter: @kkagurazaka

    View Slide

  9. coroutinesとは
    ● 中断・再開可能な計算のインスタンス
    ○ Threadクラスのように、作成して実行する
    launch(UI) {
    val token = fetchToken() // Tokenが取得できるまで実行を中断
    val item = postItem(token, newItem) // 投稿が完了するまで実行を中断
    updateUI(item)
    }

    View Slide

  10. どのように中断・再開を
    実現しているのか?

    View Slide

  11. suspending function

    View Slide

  12. suspending function
    ● 呼び出されるとcoroutinesを中断する(こともできる)
    ● suspending functionはcoroutinesかsuspending functionか
    らしか呼び出せない
    ● Java byte codeになる際にCPS transformされる

    View Slide

  13. suspending function
    ● 呼び出されるとcoroutinesを中断する(こともできる)
    ● suspending functionはcoroutinesかsuspending functionか
    らしか呼び出せない
    ● Java byte codeになる際にCPS transformされる

    View Slide

  14. Continuation Passing Style (CPS)
    戻り値で値を返すのではなく、引数のContinuationインスタンスに
    結果を渡すことで値を伝達するスタイル
    interface Continuation {
    // 成功したことと、その結果を伝達
    fun resume(value: T): Unit
    //失敗したことと、原因の例外を伝達
    fun resumeWithException(exception: Throwable): Unit
    }

    View Slide

  15. CPS transform
    // Kotlinでの宣言
    suspend fun fetchToken(): Token
    // 変換後のJava byte codeをKotlinっぽく書いたもの
    fun fetchToken(continuation: Continuation): Any?
    ● 中断する場合は COROUTINE_SUSPENDED 定数を返し、
    再開するときにContinuationをresumeする
    ● 中断しない場合は結果の T を返す

    View Slide

  16. 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を介した
    コールバックに変換される

    View Slide

  17. 内部的な実装とはいえ
    コールバックのネストが
    深すぎないか?

    View Slide

  18. ステートマシンによる実装
    class StateMachine implements Continuation {
    int label = 0; // ステートマシンの状態
    Token token; // suspending functionのローカル変数
    Item item; // 同上
    void resume(Object data) { … }
    }

    View Slide

  19. 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;
    }
    }

    View Slide

  20. 内部実装がコールバックヘル
    というわけではない!

    View Slide

  21. まとめ
    ● coroutineの中断はsuspending functionで発生する
    ● suspending functionはCPS transformによってコールバック
    に変換される
    ● 複数のsuspending functionの呼び出しはステートマシンにコ
    ンパイルされる

    View Slide

  22. Thanks!

    View Slide