Channel
Deferred objects provide a convenient way to pass values between coroutines. Channel is used to pass a stream of values between coroutines.
Channel is a bit similar to BlockingQueue. The difference is that BlockingQueue's put and take operations are blocking, while Channel's send and receive are non-blocking that can be suspended.
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!")
}
Unlike Queue, the channel can be closed. For the closing of the channel, we can use close (). The value transmitted before closing will still be received at the receiving end. The receiving end traverses the received value through a for loop:
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!")
}
In the previous blog post, we introduced that when the launch of flow is too fast and the processing speed is too slow, you can take corresponding measures. You can return a ReceiveChannel through produce , and the receiver traverses through consumeEach , as follows:
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!")
}
By defining extension functions on CoroutineScope to create coroutines to achieve structured concurrency, avoid using global coroutines Scope (GlobalScope) everywhere, coroutines created by producers can be nested and called as follows:
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)
}
Fan-out and fan-in of channel
Buffered channels 和 Ticker channels
Multiple coroutines may receive values from the same channel. This situation is called Fan-out.
Multiple coroutines may transmit values to the same channel. This situation is called Fan-in.
Channel can be set to a buffer size when it is defined, similar to BlockingQueue.
Considering that these scenes are not used much, I will not introduce them for the time being. If you want to know, you can directly move to the official website document: https://kotlinlang.org/docs/reference/coroutines/channels.html