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

Kotlinのコルーチンについて

 Kotlinのコルーチンについて

More Decks by 虎の穴ラボ株式会社

Other Decks in Technology

Transcript

  1. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 2.コルーチンについて 7 • 「コルーチン」はWikipediaには以下のよう に書かれています。 Copyright © 2019 Toranoana

    Inc. All Rights Reserved. コルーチン(英: co-routine)とはプログラミングの構造の 一種。 サブルーチンがエントリーからリターンまでを一つの 処理単位とするのに対し、コルーチンはいったん処 理を中断した後、続きから処理を再開できる。 接頭辞 co は協調を意味するが、複数のコルーチンが中 断・継続により協調動作を行うことによる。 (「コルーチン」『フリー百科事典 ウィキペディア日本語版』。 2019年6月4日 (火) 17:00 UTC、 URL: https://ja.wikipedia.org )
  2. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 11 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    • Kotlinのコルーチンについて Webサイトには以下のように説明されています。 3.コルーチンの概要 One can think of a coroutine as a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate. The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance. True threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine. 「Your first coroutine with Kotlin – Kotlin Programming Language (https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html )」より、記述の一 部を抜粋して引用
  3. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 12 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    • Kotlinのコルーチンについて 3.コルーチンの概要  コルーチンは軽量のスレッドと考えることができます。スレッド と同様に、コルーチンは並行して実行でき、互いに待機して通 信ができます。最大の違いは、コルーチンはリソースの要求コ ストが非常に低いということです。これにより私たちは何千もの コルーチンを作成することができます。その一方で、本来のス レッドは非常にコストがかかります。現代のマシンでは、1000 個のスレッドの作成が深刻な問題になる場合もあります。 「Your first coroutine with Kotlin – Kotlin Programming Language (https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html )」より、記述の一部を抜粋し て引用したものを翻訳したものです
  4. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 13 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    ・軽量なスレッドのようなもの ・(呼び出し元の)スレッドをブロックせずに非同期に動作さ せることができる ・互いに通信ができる ・軽量な為、大量に作成することができる ・ Kotlinのコルーチンは「非対称コルーチン」と呼ばれるも ので、中断時に呼び出し元に制御をいったん戻します 3.コルーチンの概要
  5. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 15 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    ・・・ざっくりと説明していきいます。 4.Kotlinのコルーチン用語 用語 説明 CoroutineDispatcher コルーチンが動作するスレッドを指定できます CoroutineContext コルーチンを動作させる為の様々な要素を含むイン スタンス。CoroutineDispatcher も含みます CoroutineScope CoroutineContextを所持するインスタンス Coroutine builder コルーチンを作成する為の関数 suspending functions コルーチンを中断状態にすることのできる関数で す。 コルーチン、またはサスペンド関数からのみ実行す ることができます。
  6. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 16 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    1.コルーチンディスパッチャ  コルーチンは呼び出し元のスレッド以外のスレッ ドで動作をさせることで非同期に動作させます。 ディスパッチャはそのスレッドを指定する為のもの です。 4.Kotlinのコルーチン用語
  7. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 17 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    1.コルーチンディスパッチャ コルーチンの中断前後で同一のスレッドが担当す るとは限りません。 4.Kotlinのコルーチン用語
  8. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 18 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    2.コルーチンコンテキスト  コルーチンを動作させる為の様々な要素を含む インスタンスです。ディスパッチャも含みます。 4.Kotlinのコルーチン用語
  9. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 19 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    3.コルーチンスコープ  コンテキストとディスパッチャを所持するインスタ ンスです。  ユーザーの任意で作成することもできます。  また、スコープの中にスコープの作成もできま す。 4.Kotlinのコルーチン用語
  10. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 20 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    4.コルーチンビルダー  コルーチンを作成する為の関数です。  runBuilder()を除く関数がコルーチンスコープの 拡張関数となっている為、基本的にコルーチン は、何かしらのコルーチンスコープに所属すること になります。 4.Kotlinのコルーチン用語
  11. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 21 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    4.コルーチンビルダー  コルーチンスコープに所属することで、コンテキ ストの指定範囲、コルーチンの例外の影響範囲な どを狭めることができます。 4.Kotlinのコルーチン用語
  12. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 22 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.サスペンド関数  コルーチンを中断状態にできる関数です。ユー ザー側で定義することもできます。   サスペンド関数は、コルーチンまたはサスペンド 関数からのみ呼び出すことができます。  中断状態となったコルーチンは、呼び出し元に制 御を一旦戻します。 4.Kotlinのコルーチン用語
  13. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 23 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    ふわっとしたまとめ ・コルーチンスコープ:  コルーチンを作成するのに必要です。 ・ コルーチンビルダー:  コルーチンを作成する為の関数です。 ・サスペンド関数:  コルーチンを中断状態にできる関数です。 4.Kotlinのコルーチン用語
  14. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 25 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    ここからはKotlinのリファレンスガイドで説明されて いるコードを実際に動かしながら、コルーチンの動 作を見て行きます。 Coroutines Guide - Kotlin Programming Language https://kotlinlang.org/docs/reference/coroutines /coroutines-guide.html 5.コルーチンの動作
  15. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 26 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    ・スレッドをブロックせずに動作するのを確認 ・コルーチンの完了を待つ ・コルーチンのタイムアウトを待つ ・依存関係の無い、2つのコルーチンの戻り値を得 る ・コルーチンとの通信を行う 5.コルーチンの動作
  16. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 27 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    スレッドをブロックせずに 動作するのを確認 5.コルーチンの動作
  17. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 28 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking<Unit> { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") delay(2000L) } 実行結果 Hello, ← 実行してすぐに表示 World! ← 実行して 1秒後に表示
  18. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 29 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking<Unit> { GlobalScope.launch { ← ❶コルーチンを作成 delay(1000L) ← ❷中断して呼び出し元に戻る println("World!") ← ❺1秒後に再開して、”World!”を出力 } println("Hello,") ← ❸”Hello,”を出力 delay(2000L) ← ❹2秒間スリープ } コルーチンが中断状態となっても、メインスレッド が動作しているのが確認できます。
  19. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 30 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・runBlocking  コルーチンビルダー。  コルーチンを作成しておきながら、中断関数で中 断しても、呼び出し元に返さずにブロックしてしま います。  runBlocking {...}は、トップレベルのメインコルー チンを起動する為に使用してください。 5.コルーチンの動作
  20. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 31 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・GlobalScope  アプリケーションの有効期間全体にわたって動 作するグローバルなコルーチンスコープです。  アプリケーションコードは通常、(GlobalScopeで はなく)アプリケーション定義のコルーチンスコープ を使用する必要があります。 5.コルーチンの動作
  21. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 32 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・launch  コルーチンビルダー。  コルーチンの実行途中のキャンセルや、コルー チンの処理の完了を待つことができる、Jobインタ フェースを持つインスタンスを返します。   5.コルーチンの動作
  22. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 33 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・delay  サスペンド関数。  スレッドをブロックせずに一定時間コルーチンを 遅らせ、指定時間後に再開します。 この中断機能 はキャンセルが可能です。   5.コルーチンの動作
  23. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 35 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { val job = GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") job.join() } 実行結果 Hello, ← 実行してすぐに表示 World! ← 実行して 1秒後に表示
  24. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 36 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { val job = GlobalScope.launch { ← ❶ 新しいコルーチンを起動し、その参 照を取得 delay(1000L) println("World!") } println("Hello,") job.join() ← ❷ コルーチンの処理が完了するまで待ちます } job.join()により、コルーチンの完了を待っている のが確認できます。
  25. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 37 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・join()  launch コルーチンビルダーが返す Job インスタ ンスが持つサスペンド関数。  コルーチンの完了を待つことができます。  他にJobインスタンスでは、cancel()によりコルー チンのキャンセルなども行えます。   5.コルーチンの動作
  26. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 39 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { withTimeout(1300L) { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } } 実行結果 I'm sleeping 0 ... I'm sleeping 1 ... I'm sleeping 2 ... Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms
  27. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 40 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { withTimeout(1300L) { ← ❶ 指定時間が経過すると、 TimeoutCancellationExceptionが発生します repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } } withTimeoutによってスローされる TimeoutCancellationExceptionにより、コルーチンがキャン セルされるのが確認できます。
  28. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 41 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・withTimeout()  コルーチン内の指定されたコードブロックを実行 し、タイムアウト時間を超えた場合は TimeoutCancellationException をスローします。  コルーチンの中では TimeoutCancellationException は コルーチンの完了の通常の理由であると見なされ ます。 5.コルーチンの動作
  29. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 42 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    依存関係の無い、 2つのコルーチンの戻り値を得る 5.コルーチンの動作
  30. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 43 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) // pretend we are doing something useful here return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // pretend we are doing something useful here, too return 29 }
  31. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 44 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 実行結果 The answer is 42 Completed in 1051 ms fun main() = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } ← ❶ コルーチン起動 val two = async { doSomethingUsefulTwo() } ← ❶ コルーチン起動 println("The answer is ${one.await() + two.await()}") ← ❷ 2つのコ ルーチンの完了と戻り値を待ち、出力 } println("Completed in $time ms") }
  32. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 45 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } ← ❶ コルーチン起動 val two = async { doSomethingUsefulTwo() } ← ❶ コルーチン起動 println("The answer is ${one.await() + two.await()}") ← ❷ 2つのコ ルーチンの完了と戻り値を待ち、出力 } println("Completed in $time ms") } それぞれ別の関数を実行するコルーチンの完了を待ち、そ れぞれの戻り値を得て計算が行えているのが確認できま す。
  33. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 46 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・async  コルーチンビルダー。  コルーチンを作成し、戻り値としてDeferredの実 装を返します。DeferredはJobインタフェースを継 承している為、Job同様、実行中のコルーチンの キャンセルや完了の待機なども可能です。 5.コルーチンの動作
  34. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 47 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・await()  Deferredの関数。 スレッドをブロックせずに完了を待ち、完了すると 再開し、結果の値を返すか、取り消された場合は 対応する例外をスローします。 5.コルーチンの動作
  35. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 49 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { val channel = Channel<Int>() launch { for (x in 1..5) channel.send(x * x) } // ここでは5つの受信整数を表示します: repeat(5) { println(channel.receive()) } println("Done!") } 実行結果 1 4 9 16 25 Done!
  36. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 50 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    5.コルーチンの動作 fun main() = runBlocking { val channel = Channel<Int>() launch { for (x in 1..5) channel.send(x * x) ← ❶ 計算結果を channel に送信 } // ここでは5つの受信整数を表示します: repeat(5) { println(channel.receive()) } ← ❷ channel から受信して表示 println("Done!") } コルーチン内部で順次送信される計算結果を、メインスレッ ド側で受信して表示できているのが確認できます。
  37. 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 51 Copyright © 2019 Toranoana Inc. All Rights Reserved.

    用語説明 ・Channel  コルーチン用の通信用チャンネル。  関数として sendとreceiveを持ち、これにより通 信が行えます。  これは現在のところ実験的(experimental)な実 装になっているので注意してください。 5.コルーチンの動作