チャネル
遅延オブジェクトは、コルーチン間で値を渡すための便利な方法を提供します。チャネルは、コルーチン間で値のストリームを渡すために使用されます。
チャネルは、BlockingQueueに少し似ています。違いは、BlockingQueueのputおよびtake操作がブロックされているのに対し、チャネルの送信および受信は一時停止可能な非ブロックであることです。
fun main() = runBlocking {
val channel = Channel<Int>()
launch {
// this might be heavy CPU-consuming computation or async logic, we'll just send five squares
for (x in 1..5) channel.send(x * x)
}
// here we print five received integers:
repeat(5) { println(channel.receive()) }
println("Done!")
}
Queueとは異なり、チャネルを閉じることができます。チャネルを閉じるには、close()を使用できます。閉じる前に送信された値は、受信側で引き続き受信されます。受信側は、forループを介して受信した値をトラバースします。
fun main() = runBlocking {
val channel = Channel<Int>()
launch {
for (x in 1..5) channel.send(x * x)
channel.close() // we're done sending
}
// here we print received values using `for` loop (until the channel is closed)
for (y in channel) println(y)
println("Done!")
}
前回のブログ投稿で、フローの起動が速すぎて処理速度が遅すぎる場合に、対応する対策を講じることができることを紹介しました。次のように、produce を介して ReceiveChannel を返し、consumeEach を介してレシーバがトラバースします。
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
for (x in 1..5) send(x * x)
}
fun main() = runBlocking {
val squares = produceSquares()
squares.consumeEach { println(it) }
println("Done!")
}
CoroutineScopeで拡張関数を定義して構造化された同時実行性を実現するコルーチンを作成し、グローバルコルーチンスコープ(GlobalScope)をどこでも使用しないようにすることで、プロデューサーによって作成されたコルーチンを次のようにネストして呼び出すことができます。
fun main() = runBlocking {
val numbers = produceNumbers() // produces integers from 1 and on
val squares = square(numbers) // squares integers
repeat(5) {
println(squares.receive()) // print first five
}
println("Done!") // we are done
coroutineContext.cancelChildren() // cancel children coroutines
}
fun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
for (x in numbers) send(x * x)
}
チャンネルのファンアウトとファンイン
バッファリングされたチャネルとティッカーチャネル
複数のコルーチンが同じチャネルから値を受け取ることがあります。この状況はファンアウトと呼ばれます。
複数のコルーチンが同じチャネルに値を送信することがあり、この状況はファンインと呼ばれます。
チャネルは、BlockingQueueと同様に、定義時にバッファサイズに設定できます。
これらのシーンはあまり使われていないので、とりあえず紹介しませんが、知りたい場合は、公式サイトのドキュメントhttps://kotlinlang.org/docs/reference/coroutines/channels.htmlに直接移動できます。