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!")
}
请注意,这次不需要消耗它们中的任何一个。
我知道通道是实验性的,我们可以将通道视为 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!")
}
请注意,这次不需要消耗它们中的任何一个。