Kotlin 1.3: コルーチンコンテキストとディスパッチャ (2/3)


Kotlin 1.3: コルーチンコンテキストとディスパッチャ (1/3)の続きです。

検証環境

  • Kotlin 1.3.0-rc-146
  • kotlinx-coroutines-core 0.30.2

スレッド間ジャンプ

次のコードを JVM オプション -Dkotlinx.coroutines.debug をつけて実行してみます。

ここではいくつかの新しい技術を使っています。 runBlocking を 明示的に特定のコンテキストで実行しています。 そして、 同一のコルーチン内で withContext 関数 を使って コルーチンのコンテキストを変更しています。 出力を見るとそれがわかります。

このサンプルコードでは、 Kotlin 標準関数 の user を使っています。Note, that this example also uses use function from the Kotlin standard library to release threads that are created with newSingleThreadContext when they are no longer needed

コンテキスト内のジョブ

コルーチンのジョブはそのコンテキストの一部です。 コルーチン内では coroutineContext[Job] 式 を使って コンテキストを取得することができます。 次に例を示します。

出力は次のようになります。

CoroutimeScopeisActive プロパティ は、 実質的に croutineContext[Job]isActive プロパティ へのエイリアスになっています。

コルーチンの子ども

コルーチン が 別のコルーチンの CoroutineScope で起動された場合、 起動されたコルーチンは CoroutineScope.coroutineContext を経由してコンテキストを継承し、 新しいコルーチンのジョブを親のコルーチンのジョブとして追加します。 親のコルーチンがキャンセルされたら、子のコルーチンも再帰的にキャンセルされます。

GlobalScope がコルーチンの起動に使われた場合、 起動されたところのスコープには追加されず、 独立して実行されます。

アウトプットは次のようになります。

実行開始から 約 1500 ms 待った時の出力です。 (“約”と書いているのは println の処理時間があるからです。) ジョブがキャンセルされていなければ、 1100 ms ほど待ったところで、 “job2” の出力が出るはずです。 子のコルーチンとして再帰的にキャンセルされているので出力されていません。

親の責任

親のコルーチンは常に全ての子のコルーチンの完了を待ちます。 親のコルーチンでは、 明示的に全ての子のコルーチンをトラッキングさせる必要はなく、 Job.join を実行する必要もありません。 次にサンプルコードを示します。

出力結果は次のようになります。

確かに 最初の launch 内 で作られた子のコルーチンは全て、 親の処理が先に終わっても、実行されています。 例えば 下から 3行目にある join の行をコメントアウトして実行すると次のような出力になります。

join を実行していないので、 runBlocking 内 の println が最初に実行されていますが、 runBlocking 内 で起動されたコルーチンは全て最後まで実行されています。 (Kotlin 1.3: Coroutine の基本 (1 of 2) で見た通りですね。)

デバッグのためにコルーチンに名前をつける

自動的に付与された ID は コルーチンがログを頻繁に出力し、 それをコルーチンごとにまとめるだけであれば有効です。 しかし、 コルーチンが特定のリクエストまたは特定のバックグラウンドタスクと結びついている場合には、 デバッグのために明示的に命名するのが適しています。 CoroutineName コンテキスト は スレッド名と同じ機能を有しています。 デバッグモードが有効である場合に、 そのコルーチンが実行されているスレッド名の中に表示されます。

以下がサンプルコードです。

出力は次のようになります。

ドキュメントによれば、次のようになるはずなのですが、そうなりませんでした。

次のようにコードを変更すると、指定した名称が出力されるようになりました。

出力は次のようになりました。

コンテキストを結びつける

時には複数の要素をコルーチンのコンテキストに指定する必要があります。 それは + 演算子を使うことで可能になります。 例として、 コルーチンを明示的に指定されたディスパッチャで起動し、明示的に名前を指定する場合のコードを示します。

デバッグモードで実行すると次のような出力が得られます。

Kotlin 1.3: コルーチンコンテキストとディスパッチャ (3/3) に続きます。