Kotlin - 协程通道 - 它们会阻塞调用线程吗?

Kotlin - coroutines Channels - do they block the calling thread?

我知道通道是实验性的,我们可以将通道视为 java 中的阻塞队列。话虽如此,让我们来看看这个简单的 block of code:

fun main(args: Array<String>) {

    val channel = Channel<Int>()
    GlobalScope.launch {
        for (x in 1..50000) {
            println("from channel $x")
            channel.send(x * x)
        }
    }
    // here we print five received integers:
    runBlocking {repeat(5) { println(channel.receive()) }}
    println("Done!")

}

我想知道其余的整数会怎样。查看 运行 的输出:

 from channel 1
1
from channel 2
from channel 3
4
9
from channel 4
from channel 5
16
from channel 6
25
Done!

为什么它不打印所有 50000 个整数?我在全球范围内拥有它。所以这一行:println("from channel $x") 应该被调用了 50000 次。为什么没有呢?

send 是一个挂起函数,如果另一端没有 receive/dequeue 则阻塞协程(不是线程)。这就是协程世界支持背压的方式。您的 runBlocking 仅重复 5 次迭代并且您的主要退出。

通道内部队列的默认容量为 1。它是一个 so-called 会合点 通道,因为生产者和消费者协程必须相遇才能交换物品。由于您只消耗了五个项目,因此生产者只能生产其中的五个并在交付第六个之前暂停,此时您的整个程序完成。

所以,这里是打印所有 50,000 项的程序的修改:

fun main() {
    val channel = Channel<Int>(Channel.UNLIMITED)
    GlobalScope.launch {
        for (x in 1..50000) {
            println("from channel $x")
            channel.send(x * x)
        }
    }
    Thread.sleep(1000)
    println("Done!")
}

请注意,这次不需要消耗它们中的任何一个。