コルーチンの基本

kotlinlang.org

コルーチンとは

About Coroutines

Kotlinの非同期関数。 スレッドと違い、何千個作成してもCPUの負荷を増大させない

最初のコルーチン

Coroutineは、CoroutinScope内部で実行し、CoroutineScopeは、実行されたCoroutineが全て完了するまで、自身を終了させない。

// kotlinxをインポートする
import kotlinx.coroutines.*

fun main() = runBlocking { // this: CoroutineScope
    launch { // Coroutineの生成 (async)
        delay(5000L) // サスペンド関数 (await)
        println("World")
    }
    println("Hello")
}
/* 出力
Hello 
World
*/
  • runBlocking : CoroutineScopeの生成関数
  • launch : Coroutineの生成関数。CoroutineScopeに属するメソッド
  • delay() : サスペンド関数。コルーチンを停止するが、カレントスレッドをブロックしない。awaitにあたる

サスペンド関数の生成

サスペンド関数

Suspending functions can be used inside coroutines just like regular functions, but their additional feature is that they can, in turn, > use other suspending functions (like delay in this example) to suspend execution of a coroutine.

コルーチンの実行を中断する。つまりサスペンド関数自体が、awaitに相当する。

suspend修飾子をつける。また内部でサスペンド関数を呼ぶことができる。

suspend fun doWorld() {
    delay(5000L) // 内部でサスペンド関数を呼ぶことができる
    println("World")
}

fun main = runBlocking { // this: CoroutineScope
    launch { doWorld() }
    println("Hello")
}

/*
Hello
World
*/

スコープビルダー

CoroutinScopeの生成は以下がある。

coroutineScope{}は、サスペンド関数なので、runBlocking{}で一旦スコープを生成する必要がある。

coroutineScope使用例

import kotlinx.coroutines.*

fun main() {
    runBlocking { 
        doWorld() // サスペンド関数 (await)
        println("runBlocking end")
    }
    println("main end")
}

suspend fun doWorld() = coroutineScope { // this: CoroutineScope
    launch {
        delay(1000L)
        println("World")
    }
    println("Hello")
}

/* 出力結果
Hello
World
runBlocking end
main end
*/

スコープの生成と並列性

coroutineScope {}は内部に複数の並列処理を実行するためのサスペンド関数を含めることができる。

import kotlinx.coroutines.*

fun main() = runBlocking {
    doWorld() // サスペンド関数 (await)
    println("Done")
}

suspend fun doWorld() = coroutineScope { // this: CoroutineScope
    launch { // async
        delay(2000L)  // await
        println("World 2")
    }
    launch { // async
        delay(1000L) // await
        println("World 1")
    }
    println("Hello")
}

/*
Hello
World 1
World 2
Done
*/

明示的なjob

An explicit job

launchコルーチンビルダーは、Jobオブジェクトを返すので、それを使って、コルーチンの完了を明示的に待機させることができる。

job object: 起動されたコルーチンに対するハンドル

例として、子供のコルーチンの完了を待機させる

// CoroutineScope内部

val job = launch { // async
    delay(1000L) // await
    println("World")
}
println("Hello")
job.join() // 子供のコルーチンが完了するまで待機する
println("Done")

/*
Hello
World
Done
*/

コルーチンは軽量である

スレッドと違い、コルーチンを何千個生成してもCPUの負荷に影響を与えない。

import kotlinx.coroutines.*

fun main() = runBlocking {
    repeat(100_000) { // launch a lot of coroutines
        launch {
            delay(5000L)
            print(".")
        }
    }
}