本节介绍通道----Channels(官方文档)
Deferred values提供了一种在协程之间传递单个值的简便方式,通道(channels)则提供了在协程间传递流的方法。
1、Channel basics
熟悉Java的读者应该都知道阻塞队列BlockingQueue,而这里说的通道在概念上则与BlockingQueue非常相似,一个重要的区别是通道使用的是suspend的send方法存储数据而BlockingQueue使用的是阻塞的put方法,同时在取数据的时候通道使用的是suspend的receive而BlockingQueue使用是阻塞的take,代码如下:
package com.cool.cleaner.test
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking<Unit> {
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!")
}
输出如下:
1
4
9
16
25
Done!
Process finished with exit code 0
2、通道的关闭及迭代
与队列不一样的是通道可以被关闭以表示没有元素会再被发射出去,在接收端可以使用for循环方便地接收通道里面的数据。
从概念上讲close就像是发射了一个特殊的标识(token)到通道中,在接收端只要收到相应的token就会马上结束迭代,所以就可以保证在token发射之前的所有数据都会被接收到,如下代码所示:
package com.cool.cleaner.test
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking<Unit> {
val channel = Channel<Int>()
launch {
for (x in 1..9) {
if (x >= 7) {
channel.close()//we're done sending
break
} else {
channel.send(x * x)
}
}
}
// here we print received values using 'for'
// loop(until the channel is closed)
for (value in channel) {
println(value)
}
println("Done!")
}
3、通道生产者(Building channel producers)
在协程中生成一系列的元素这种模式是非常普遍的,这是在并发编程中经常遇到的生产者----消费者模式的一部分;你可以将通道作为参数传递给一个函数并封装成一个生产者,但是这违背了结果必须从函数中返回的一种认知常识。
在协程中有一个协程构建器produce可以使得构建生产者更容易,而扩展函数consumeEach则作为消费者端替代了for循环的功能,代码如下:
package com.cool.cleaner.test
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.channels.produce
import kotlinx.coroutines.runBlocking
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
for (value in 1..5) send(value * value)
}
fun main() = runBlocking<Unit> {
val squares = produceSquares()
squares.consumeEach { println(it) }
println("Done!")
}
4、Pipelines
一个pipeline就是一个协程产生无限(可能)的值,代码如下: