与FlowCollector中的emit()函数不同,yield函数在取消协同例程时不协同工作。以下是示例程序:
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeoutOrNull
fun main(): Unit = runBlocking {
withTimeoutOrNull(5000) {
getFlow().collect { println("printing flow iteration $it on ${Thread.currentThread().name}") }
}
withTimeoutOrNull(5000) {
getSequence().forEach { println("printing sequence iteration $it on ${Thread.currentThread().name}") }
}
}
fun getSequence() = sequence<Int> {
for (i in 1..10) {
wasteCpuCycles(1000)
yield(i)
}
}
fun getFlow() = flow<Int> {
for (i in 1..10) {
wasteCpuCycles(1000)
emit(i)
}
}
fun wasteCpuCycles(durationInMillis: Int) {
val endTime = System.currentTimeMillis() + durationInMillis
while (endTime >= System.currentTimeMillis()) {
}
}
以下是执行的输出:
在main上打印流程迭代1
在main上打印流程迭代2
在main上打印流程迭代3
在main上打印流程迭代4
在main上打印序列迭代1
在main上打印序列迭代2
在main上打印序列迭代3
在main上打印序列迭代4
在main上打印序列迭代5
在main上打印序列迭代6
在main上打印序列迭代7
在main上打印序列迭代8
在main上打印序列迭代9
在main上打印序列迭代10
根据that和emit函数的签名,我希望这两个函数都参与协作例程的协作取消。但是通过查看输出可以发现,即使协同例程从超时中取消,产量也不会停止。由于两者都挂起了功能,这种行为背后的原因可能是什么?
发布于 2021-06-10 15:45:58
与flow不同,序列不是异步的。因此,SequenceScope内部的收益函数是不可取消的,并且对协同例程的运行状态没有影响。
发布于 2021-06-10 16:53:15
请注意,sequence { }
函数和next()
都是不可挂起的,它们也不会接收协程上下文/作用域。我猜这意味着在序列中运行的协程没有附加到调用者的协程上下文中,它不参与其结构化并发。因此,即使withTimeoutOrNull()
取消了在其中运行的协程,sequence { }
内部的协程也会从上面分离出来,并且不会被通知取消。
至少这是我的理解,我可能会错过一些东西。
https://stackoverflow.com/questions/67916479
复制相似问题