Introduce Kotlin Coroutine(@CA.kt_2017/06)

Daec7e5cd5fae384eda88037d937343b?s=47 AAkira
June 15, 2017

Introduce Kotlin Coroutine(@CA.kt_2017/06)

CA.kt @CyberAgent
Introduce Kotlin Coroutine
https://cyberagent.connpass.com/event/57963/

Daec7e5cd5fae384eda88037d937343b?s=128

AAkira

June 15, 2017
Tweet

Transcript

  1. Kotlin Coroutine入門 AAkira @ CA.kt

  2. $ whois private lateinit var aakira: User data class User(val

    name: String, val twitterId: String, val githubId: String, val company: String) println("Name : ${aakira.name}") println("Twitter Id : ${aakira.twitterId}") println("Github Id : ${aakira.githubId}") println("Company : ${aakira.company}")
  3. @_a_akira AAkira CyberAgent, Inc. Akira Aratani private lateinit var aakira

    : User data class User(val name: String, val twitterId: String, val githubId: String, val company: String) print("Name : ${aakira.name}”) println("Github Id : ${aakira.githubId}") print("Twitter Id : ${aakira.twitterId}") println("Company : ${aakira.company}") $ whois
  4. @_a_akira AAkira CyberAgent, Inc. Akira Aratani private lateinit var aakira

    : User data class User(val name: String, val twitterId: String, val githubId: String, val company: String) print("Name : ${aakira.name}”) println("Github Id : ${aakira.githubId}") print("Twitter Id : ${aakira.twitterId}") println("Company : ${aakira.company}") $ whois ,PUMJOॿ૸ಡຊ΋ॻ͍ͨIUUQTHPPHM"$K')
  5. About • 生放送配信プラットフォーム ≠ AbemaTV • 最近 アプリを縦化! FRESH! AndroidアプリのUI/UX :

    https://developers.cyberagent.co.jp/blog/archives/7177 • Full Kotlin • 使ってるLibraryは大体最新
 (Kotlin1.1, Rx2, Dagger2, Retrofit2, Ok3, ExoPlayer2 etc) • もちろんコルーチンも一部で導入済み
  6. 私とKotlin M1 2012-04-12 M11 2015-03-19 M14 2015-10-01 1.0-beta4 2015-12-22 M13

    2015-09-16 1.0 2016-02-16 1.0-RC 2016-02-04 2016-01-21 Release 2015-04 開発開始 kotlin FRESH 1.1 2017-03-01 2017-05-15 Renewal
  7. About coroutine

  8. About Coroutine • Kotlin 1.1で導入された非同期プログラミングのための機能  ≠ Thread : 特定のスレッドに属していないので、再開先は別のスレッドで動作可能 •

    1.1ではまだExperimentalなので、仕様変更の可能性あり • 言語機能ではなく、ライブラリとして提供されている
  9. Introduce Coroutine def kotlinCoroutinesVersion = "0.15" // for core compile

    “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for JDK8 compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion"
  10. Introduce Coroutine // for core compile “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for JDK8

    compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion" Ұൠతͳ"OESPJEͰ։ൃͰඞཁͳϥΠϒϥϦ
  11. Elements of coroutine • Suspending functions • Coroutine builders (Suspending

    lambda) • Coroutine dispatchers (Coroutine context)
  12. Suspending functions

  13. Suspending functions • コルーチンの実行を中断することができる関数 • 通常のコードから呼び出すことはできない • 他のSuspending function, Coroutine

    Builder(Suspending lambda)からのみ 呼び出すことが可能
  14. Suspending functions suspend fun hoge(): Int { delay(10, TimeUnit.SECONDS) return

    100 } 10秒後に100を返すsuspend関数
  15. Suspending functions delayもsuspend関数 suspend fun delay(time: Long, unit: TimeUnit =

    TimeUnit.MILLISECONDS) { require(time >= 0) { "Delay time $time cannot be negative" } if (time <= 0) return // don't delay return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> -> val delay = cont.context[ContinuationInterceptor] as? Delay if (delay != null) delay.scheduleResumeAfterDelay(time, unit, cont) else cont.cancelFutureOnCompletion( scheduledExecutor.schedule(ResumeRunnable(cont), time, unit)) } }
  16. Suspending functions suspend fun hoge(): Int { delay(10, TimeUnit.SECONDS) return

    100 } hogeもsuspend関数なのでdelayを呼び出せる
  17. Suspending functions suspend関数を引数にとることも可能 foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar:

    suspend () -> String) { launch(CommonPool) { println(bar.invoke()) } }
  18. Suspending functions 10秒後に “CA.kt” と出力される foo({ delay(10, TimeUnit.SECONDS) "CA.kt" })

    fun foo(bar: suspend () -> String) { launch(CommonPool) { println(bar.invoke()) } }
  19. Suspending functions foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar: suspend

    () -> String) { launch(CommonPool) { println(bar.invoke()) } }
  20. Coroutine builders (Suspending lambda)

  21. Coroutine builders • 引数として(複数の)Suspending Lambdaを取ってコルーチンを作成し、 オプションでその結果へのアクセスを与える関数

  22. Coroutine builders Name Result Scope Description launch Job CoroutineScope Launches

    coroutine that does not have any result async Deferred CoroutineScope Returns a single value with the future result produce ProducerJob ProducerScope Produces a stream of elements actor ActorJob ActorScope Processes a stream of messages runBlocking T CoroutineScope Blocks the thread while the coroutine runs IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFT
  23. launch 結果を返さない(Unit)コルーチンを作る public fun launch( context: CoroutineContext, start: CoroutineStart =

    CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job {
  24. launch • 第一引数のCoroutineContextはスレッドの様な実行環境を指定する(次節で解説) • 第二引数のCoroutineStartはコルーチンを開始するタイミングを指定できる public fun launch( context: CoroutineContext,

    start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job {
  25. async 結果を返すコルーチンを作る public fun <T> async( context: CoroutineContext, start: CoroutineStart

    = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T> {
  26. launchとasyncの違い • launchはJobを返す • asyncはDeferred<T>を返す • DeferredはJobのinterface public interface Deferred<out

    T> : Job { val isCompletedExceptionally: Boolean val isCancelled: Boolean public suspend fun await(): T public fun <R> registerSelectAwait(select: SelectInstance<R>, block: suspend (T) -> R) public fun getCompleted(): T }
  27. Others (Coroutine builders) • 入門としてはlaunchとasyncが使えれば問題ない • produce, actorはgoroutineのようなChannelの概念がある
 produce: sender,

    actor: receiver • runBlockingはその名の通りスレッドを止めて動作する cf: https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md
  28. Coroutine dispatchers (Coroutine context)

  29. Coroutine dispatchers Name Description CommonPool Confines coroutine execution to a

    shared pool of threads newSingleThreadContext Create new single-threaded coroutine context newFixedThreadPoolContext Creates new thread pool of a fixed size Executor.asCoroutineDispatcher Extension to convert any executor Unconfined Does not confine coroutine execution in any way IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFT
  30. CommonPool java.util.concurrent.ForkJoinPoolを使って
 スレッドプールを作成して良い感じにやってくれる launch(CommonPool) { }

  31. newSingleThreadContext thread poolが1のCoroutine Dispatcherを作成する launch(newSingleThreadContext("thread name")) { }

  32. newFixedThreadPoolContext • newSingleThreadContextのthread pool数を指定できる版 • ソースの中身は一緒 launch(newFixedThreadPoolContext(3, "thread name")) {

    }
  33. asCoroutineDispatcher java.util.concurrentのExecutorをCoroutine Contextに変換出来る class MyCoroutineExecutor : Executor { override fun

    execute(command: Runnable?) { } } val myCoroutineExecutor = MyCoroutineExecutor() launch(myCoroutineExecutor.asCoroutineDispatcher()) { }
  34. Unconfined • 特定のスレッドに依らないCoroutine Context • コルーチンを再開後に特定のスレッドかスレッドプールに限定する必要が あるが、最初の中断まで現在の呼び出しスレッドで実行したい場合は、前 述のCoroutineBuilderにCoroutineStart.UNDISPATCHEDを設定する launch(Unconfined) {

    }
  35. How to use a Coroutine

  36. さっき読めなかったやつ foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar: suspend ()

    -> String) { launch(CommonPool) { println(bar.invoke()) } }
  37. おさらい Kotlinはメソッドの最後の引数が関数の場合、カッコの外に書ける
 上と下のhogeメソッド呼び出しは一緒の意味 hoge(1, { }) hoge(1) { } fun

    hoge(foo: Int, bar: () -> Unit) { }
  38. おさらい 第二引数はデフォルト引数が設定されているので、
 呼び出し時に指定しなくても良い public fun launch( context: CoroutineContext, start: CoroutineStart

    = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job {
  39. さっき読めなかったやつ foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar: suspend ()

    -> String) { launch(CommonPool) { println(bar.invoke()) } } 引数に取ったbar suspend関数を実行するコルーチンを
 良い感じのスレッドで実行して結果を出力
  40. Example 1 suspend fun foo(): String { println("---foo--- : ${Thread.currentThread().name}")

    delay(3, TimeUnit.SECONDS) return "CA.kt" }
  41. Example 1-1 fun main() { println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) {

    println("----1---- : ${Thread.currentThread().name}") println(foo()) println("----2---- : ${Thread.currentThread().name}") } println("----3---- : ${Thread.currentThread().name}”) }
  42. Example 1-1 ----0---- : main ----3---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----2---- : ForkJoinPool.commonPool-worker-1 fun main() { println("----0----- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1----- : ${Thread.currentThread().name}") println(foo()) println("----2----- : ${Thread.currentThread().name}") } println("----3----- : ${Thread.currentThread().name}”) }
  43. Example 1-1 ----0---- : main ----3---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----2---- : ForkJoinPool.commonPool-worker-1 ※ Threadの数字は実行環境によって変わるので、気にしなくても大丈夫です
  44. Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}")
  45. Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}") Deferred<T>.await() => 実行を中断して値を返すsuspend関数
  46. Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}") ----0---- : main ----4---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----3---- : ForkJoinPool.commonPool-worker-1
  47. Example 1-3 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  48. Example 1-3 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}") Job.join() => await同様coroutineの実行完了まで待つが戻り値が無い
  49. Example 1-3 ----0---- : main ----5---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ----3---- : ForkJoinPool.commonPool-worker-1 CA.kt ----4---- : ForkJoinPool.commonPool-worker-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  50. Example 2 suspend fun foo(): String { println("---foo--- : ${Thread.currentThread().name}")

    delay(6, TimeUnit.SECONDS) return "foo" } suspend fun bar(): String { println("---bar--- : ${Thread.currentThread().name}") delay(3, TimeUnit.SECONDS) return "bar" }
  51. Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}")
  52. Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ----2---- : ForkJoinPool.commonPool-worker-1 ---bar--- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1
  53. Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ---bar--- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1 ඵ͔͔Δ ௚ྻ࣮ߦ
  54. Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}")
  55. Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ---bar--- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1
  56. Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ---bar--- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1 ඵͰऴΘΔ ฒྻॲཧ
  57. Example 3 @Android Clickしたら3秒後にtext viewにCA.ktをsetする val button: Button val textView:

    TextView suspend fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(CommonPool) { textView.text = foo() } } }
  58. Example 3 @Android Only the original thread that created a

    view hierarchy can touch its views.
  59. Example 3 @Android Main thread以外でViewの更新は出来ない val button: Button val textView:

    TextView suspend fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(CommonPool) { textView.text = foo() } } }
  60. Example 3 @Android // for core compile “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for

    JDK8 compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion" "OESPJE༻ʹ$PSPVUJOFEJTQBUDIFS͕༻ҙ͞Ε͍ͯΔ
  61. Example 3 @Android val UI = HandlerContext(Handler(Looper.getMainLooper()), "UI") fun Handler.asCoroutineDispatcher()

    = HandlerContext(this) public class HandlerContext(private val handler: Handler, private val name: String? = null) : CoroutineDispatcher(), Delay { override fun dispatch(context: CoroutineContext, block: Runnable) { handler.post(block) } override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) { handler.postDelayed({ with(continuation) { resumeUndispatched(Unit) } }, unit.toMillis(time)) } override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle { handler.postDelayed(block, unit.toMillis(time)) return object : DisposableHandle { override fun dispose() { handler.removeCallbacks(block) } } } override fun toString() = name ?: handler.toString() override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler override fun hashCode(): Int = System.identityHashCode(handler) }
  62. Example 3 @Android val button: Button val textView: TextView suspend

    fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(UI) { textView.text = foo() } } } Coroutine contextの引数をUIに置き換えると想定通りの動作
  63. Example 4 @RxJava RxJavaのBehaviorProcessorにある値を取得して出力 val fooProcessor = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- :

    ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}”) } println("----5---- : ${Thread.currentThread().name}")
  64. Example 4 @RxJava awaitFirst() => Rxのstreamからthreadをblockせずに
         値をとってくるsuspend関数 val fooProcessor

    = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  65. Example 4 @RxJava ----0---- : main ----5---- : main ----1----

    : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-2 CA.kt ----4---- : ForkJoinPool.commonPool-worker-1 val fooProcessor = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}”) } println("----5---- : ${Thread.currentThread().name}")
  66. Conclusion

  67. Conclusion • 結構手軽に非同期処理がかける • 既存のRxを置き換える必要はない
 FRESH!ではFluxのStoreから取得する場面によって使い分けている • 今回は話していないChannelも使いこなせると より便利 •

    Experimentalなので、まだ注意が必要
  68. 時間あったら • GCはどうなってるか • Bytecodeだと同処理されているか

  69. Resource management and GC fun sequenceOfLines(fileName: String) = buildSequence<String> {

    BufferedReader(FileReader(fileName)).use { while (true) { yield(it.readLine() ?: break) } } } fun main(args: Array<String>) { sequenceOfLines("examples/sequence/sequenceOfLines.kt") .forEach(::println) } DGIUUQTHJUIVCDPN,PUMJOLPUMJODPSPVUJOFT
  70. Resource management and GC • コルーチンの参照を失った場合でも最終的にはGCされる
 => GCによって収集されるまでファイルは開いたままになる fun main(args:

    Array<String>) { sequenceOfLines(“examples/sequence/sequenceOfLines.kt") .take(3) .forEach(::println) }
  71. Bytecode • 2つの中断があるコルーチン • 状態 A. 1つ目の中断の前 B. 1つ目の中断後 C.

    2つ目の中断後 val a = a() val y = foo(a).await() // suspension point #1 b() val z = bar(a, y).await() // suspension point #2 c(z)
  72. class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  73. class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  74. class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  75. class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }