Slide 1

Slide 1 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 Kotlinのコルーチンについて 株式会社 虎の穴 山田 公博 1 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 2

Slide 2 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 自己紹介 所属     :株式会社虎の穴 虎の穴ラボ 名前     :山田 公博 担当業務   :ECサイト開発 業務使用の言語:Java 今期のアニメ:「盾の勇者の成り上がり」 2 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 3

Slide 3 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 アジェンダ 1. はじめに 2. コルーチンについて 3. Kotlinのコルーチンの概要 4. Kotlinのコルーチン用語 5. Kotlinのコルーチンの動作 6. 終わりに 3 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 4

Slide 4 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 4 Copyright © 2019 Toranoana Inc. All Rights Reserved. 1.はじめに

Slide 5

Slide 5 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 1.はじめに 5 本日の目標 「なんとなくKotlinのコルーチンの事がわかっ たような気がする」ようになる事 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 6

Slide 6 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 6 Copyright © 2019 Toranoana Inc. All Rights Reserved. 2.コルーチンについて

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 2.コルーチンについて 8 ですが、その実装は用語なども含めて言語に より異なっており、「一般的なコルーチン」とい うのは捉えることができませんでした。 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 9

Slide 9 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 2.コルーチンについて 9 ですが、その実装は用語なども含めて言語に より異なっており、「一般的なコルーチン」とい うのは捉えることができませんでした。 今回はあくまで 「Kotlinのコルーチン」に限定したお話です。 以降、「コルーチン」は全て「Kotlinのコルー チン」をさします。 Copyright © 2019 Toranoana Inc. All Rights Reserved.

Slide 10

Slide 10 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 10 Copyright © 2019 Toranoana Inc. All Rights Reserved. 3.Kotlinのコルーチンの概要

Slide 11

Slide 11 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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 )」より、記述の一 部を抜粋して引用

Slide 12

Slide 12 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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 )」より、記述の一部を抜粋し て引用したものを翻訳したものです

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 14 Copyright © 2019 Toranoana Inc. All Rights Reserved. 4.Kotlinのコルーチン用語

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 24 Copyright © 2019 Toranoana Inc. All Rights Reserved. 5.Kotlinのコルーチンの動作

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 34 Copyright © 2019 Toranoana Inc. All Rights Reserved. コルーチンの完了を待つ 5.コルーチンの動作

Slide 35

Slide 35 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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秒後に表示

Slide 36

Slide 36 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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()により、コルーチンの完了を待っている のが確認できます。

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 38 Copyright © 2019 Toranoana Inc. All Rights Reserved. コルーチンのタイムアウトを待つ 5.コルーチンの動作

Slide 39

Slide 39 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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

Slide 40

Slide 40 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 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により、コルーチンがキャン セルされるのが確認できます。

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 43 Copyright © 2019 Toranoana Inc. All Rights Reserved. 5.コルーチンの動作 fun main() = runBlocking { 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 }

Slide 44

Slide 44 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 44 Copyright © 2019 Toranoana Inc. All Rights Reserved. 5.コルーチンの動作 実行結果 The answer is 42 Completed in 1051 ms fun main() = runBlocking { 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") }

Slide 45

Slide 45 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 45 Copyright © 2019 Toranoana Inc. All Rights Reserved. 5.コルーチンの動作 fun main() = runBlocking { 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") } それぞれ別の関数を実行するコルーチンの完了を待ち、そ れぞれの戻り値を得て計算が行えているのが確認できま す。

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 48 Copyright © 2019 Toranoana Inc. All Rights Reserved. コルーチンとの通信を行う 5.コルーチンの動作

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 52 Copyright © 2019 Toranoana Inc. All Rights Reserved. 以上です 5.コルーチンの動作

Slide 53

Slide 53 text

虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 虎の穴 53 Copyright © 2019 Toranoana Inc. All Rights Reserved. 一緒にKotlinを愛でませんか? 5.終わりに