検証環境
この記事の内容は、以下の環境で検証しました。
- Intellij IDEA ULTIMATE 2018.2
- Kotlin 1.3.0
- Gradle Projectで作成
- GradleファイルはKotlinで記述(KotlinでDSL)
準備
詳細は下記の準備を参照してください。
https://qiita.com/naoi/items/8abf2cddfc2cb3802daa
Cancellation is cooperative
今回のタイトルは日本語にすると意味がわかりません。
内容を理解すれば、理解できるかもしれません。
早速読み進めます。
Coroutine cancellation is cooperative. A coroutine code has to cooperate to be cancellable.
All the suspending functions in kotlinx.coroutines are cancellable.
They check for cancellation of coroutine and throw CancellationException when cancelled. However, if a coroutine is working in a computation and does not check for cancellation, then it cannot be cancelled, like the following example shows:
訳してみると
コルーチンはキャンセルに処理に対して協力的です。また、コルーチンのコードはキャンセルに対して、協力的でなければなりません。
kotlinx.coroutinesパッケージに存在するすべてのsuspend関数はキャンセルできます。
それらの関数はキャンセル状態かどうかを常にチェックしています。キャンセルが発生するとCancellationException例外が発生します。
しかし、コルーチンで、計算処理の最中などの場合は、キャンセルができません。
なるほど、タイトルの本質は、コルーチンに関する関数は常にキャンセルされているかチェックしているから、キャンセルに対応できている(協力できている)という意味だったんですね。
でも、キャンセル出来ない場合もあるそうで、そのサンプルコードも掲載されているので確認してみます。
fun main() = runBlocking {
//sampleStart
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
//sampleEnd
}
実行結果
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
main: I'm tired of waiting!
I'm sleeping 3 ...
I'm sleeping 4 ...
main: Now I can quit.
前回との大きな違いはrepeat関数を使わずにwhile文を使用しているため、キャンセルのチェックが行われていません。while文は確かに通常の計算処理と同じため、キャンセル出来ていない事が確認できます。
公式サイトには、最後にこんな一文が載っています。
Run it to see that it continues to print "I'm sleeping" even after cancellation until the job completes by itself after five iterations.
訳してみると
実行し見ると、コルーチンはキャンセルされているにもかかわらず、ジョブが完了するまで、表示をしているね。
確かにそのとおりです。
まとめ
このブロックで理解できたことは以下のことだと思います。
- kotlinx.coroutinesパッケージ内の関数はキャンセルをチェックしていること
- 上記以外はチェックしていないこと