Open bennyhuo opened 4 years ago
关于代码清单 15:
flow { // BAD!!
emit(1)
withContext(Dispatchers.IO){
emit(2)
}
}
文中提到在 flow {...}
中「不能随意切换调度器,这是因为 emit 函数不是线程安全的」。这个描述似乎不太准确:
flow
块里的代码是顺序执行的,所以两次 emit
之间似乎没有线程安全问题。
flow 这里抛出异常是为了 context preservation,限制的是不能在不同的 CoroutineContext
里 emit
。
所以这样其实是可以的:
flow {
emit(1)
val value = withContext(Dispatchers.IO) {
2
}
emit(value)
}.collect {
println(it)
}
首先感谢支持~
flow 部分在我写书的时候还是实验状态,现在已经改了不少。你提到的这个点也是当时官当文档给出的,主要是内部状态的安全性问题,不是咱们自己传入的。
当然现在的新版是不是这样,还得看具体改成什么样了,我还没有跟进。等后面有空再确认一下
关于代码清单 15: flow { // BAD!! emit(1) withContext(Dispatchers.IO){ emit(2) } }
文中提到在 flow {...} 中「不能随意切换调度器,这是因为 emit 函数不是线程安全的」。这个描述似乎不太准确:
flow 块里的代码是顺序执行的,所以两次 emit 之间似乎没有线程安全问题。
flow 这里抛出异常是为了 context preservation,限制的是不能在不同的 CoroutineContext 里 emit 。
所以这样其实是可以的: flow { emit(1) val value = withContext(Dispatchers.IO) { 2 } emit(value) }.collect { println(it) }
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
关于代码清单 15:
flow { // BAD!! emit(1) withContext(Dispatchers.IO){ emit(2) } }
文中提到在
flow {...}
中「不能随意切换调度器,这是因为 emit 函数不是线程安全的」。这个描述似乎不太准确:
flow
块里的代码是顺序执行的,所以两次emit
之间似乎没有线程安全问题。flow 这里抛出异常是为了 context preservation,限制的是不能在不同的
CoroutineContext
里emit
。所以这样其实是可以的:
flow { emit(1) val value = withContext(Dispatchers.IO) { 2 } emit(value) }.collect { println(it) }
参考官方文档:wrong-emission-withcontext。
我读了下文档里面的内容,上面写道
but code in the flow { ... } builder has to honor the context preservation property and is not allowed to emit from a different context.
这里关键是 not allowed to emit from a different context。因为 emit 实际上会调用 collect,如果切走线程的话实际上 collect 的线程也被切走了,造成上游影响下游。
所以 withContext
不包在 emit 外面的话其实是可以的,我上面的示例代码把 withContext 搬到了 emit 外面,试了下是可以正常运行的,也符合 context preservation 的要求。
嗯,get到你的点了,不过看上去跟书里的内容也不矛盾
https://www.bennyhuo.com/2020/03/14/coroutine-flow/
Flow 就是 Kotlin 协程与响应式编程模型结合的产物,你会发现它与 RxJava 非常像,二者之间也有相互转换的 API,使用起来非常方便。