Kotlin协程和在Android中的使用总结(六 通道Channel)

Channel

Deferred对象提供了一种在协程间传递值的简便方式,Channel就是用于在协程间传递一个stream的值流。

Channel有点类似于BlockingQueue,不同的是,BlockingQueue的puttake 操作都是阻塞式的,而Channel的sendreceive都是可挂起的非阻塞式。

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

你可能感兴趣的:(Kotlin)