kotlin -协程学习的第七天

91 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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实际上是一个并发安全的队列,它可以用来连接协程,实现不同协程的通信

image.png

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)
    }