Channel
Deferred对象提供了一种在协程间传递值的简便方式,Channel就是用于在协程间传递一个stream的值流。
Channel有点类似于BlockingQueue,不同的是,BlockingQueue的put 和take 操作都是阻塞式的,而Channel的send和receive都是可挂起的非阻塞式。
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,channel可以被关闭,对于channel的关闭,我们可以使用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!")
}
在前面的博文中,我们介绍过当flow的发射过快,处理速度过慢时,可以采取相应的措施,可以通过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上定义扩展函数来创建协程实现结构化的并发,避免到处使用全局的协程Scope(GlobalScope),produce创建的协程,可以嵌套调用,如下:
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)
}
channel的扇出Fan-out和扇入Fan-in
Buffered channels 和 Ticker channels
多个协程可能会从同一个channel中接收值,这种情况称为Fan-out。
多个协程可能会向同一个channel发射值,这种情况称为Fan-in。
channel可以在定义时,设置一个缓冲的大小,类似于BlockingQueue。
考虑到这些场景使用不多,暂时不多做介绍,想了解的可以直接移步官网文档:https://kotlinlang.org/docs/reference/coroutines/channels.html