持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
认识Channel
通道提供了一种在流中传输值的方法。
Channel和BlockingQueue有点相似。其中一个不同是它代替了阻塞的 put 操作并提供了挂起的 send,还替代了阻塞的 take 操作并提供了挂起的 receive
val channel = Channel<Int>()
launch {
// 这里可能是消耗大量 CPU 运算的异步逻辑,我们将仅仅做 5 次整数的平方并发送
for (x in 1..5) channel.send(x * x)
}
// 这里我们打印了 5 次被接收的整数:
repeat(5) { println(channel.receive()) }
println("Done!")
Channel实际上是一个并发安全的队列,它可以用来连接协程,实现不同协程的通信
Channel的容量
Channel实际上是一个队列,队列中一定存在缓冲区,那么一旦这个缓冲区满了,并且也一直没有人调用receive并取走函数,send就需要挂起。故意让接收端的节奏放慢,发现send总是会挂起,直到receive之后才会继续往下执行。
迭代Channel
Channel有点像序列,我们在读取的时候可以直接获取一个Channel的iterator
val channel = Channel<Int>(Channel.UNLIMITED)
val produce = GlobalScope.launch {
for( x in 1..10){
channel.send(x*x)
println("send ${x*x}")
}
}
val consumer = GlobalScope.launch {
val iterator = channel.iterator()
while (iterator.hasNext()){
val element = iterator.next()
println("receive $element")
delay(2000)
}
}
构建通道生产者
协程生成一系列元素的模式很常见。 这是 生产者——消费者 模式的一部分,并且经常能在并发的代码中看到它。 你可以将生产者抽象成一个函数,并且使通道作为它的参数,但这与必须从函数中返回结果的常识相违悖。
这里有一个名为 produce 的便捷的协程构建器,可以很容易的在生产者端正确工作, 并且我们使用扩展函数 consumeEach在消费者端替代 for 循环:
val squares = produceSquares()
squares.consumeEach { println(it) }
println("Done!")
管道
管道是一种一个协程在流中开始生产可能无穷多个元素的模式
fun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // 在流中开始从 1 生产无穷多个整数
}
并且另一个或多个协程开始消费这些流,做一些操作,并生产了一些额外的结果
fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
for (x in numbers) send(x * x)
}