bennyhuo / Bennyhuo

bennyhuo.vercel.app
8 stars 3 forks source link

破解 Kotlin 协程(11) - Flow 篇 | Bennyhuo #33

Open bennyhuo opened 4 years ago

bennyhuo commented 4 years ago

https://www.bennyhuo.com/2020/03/14/coroutine-flow/

Flow 就是 Kotlin 协程与响应式编程模型结合的产物,你会发现它与 RxJava 非常像,二者之间也有相互转换的 API,使用起来非常方便。

yujinyan commented 3 years ago

关于代码清单 15:

flow { // BAD!!
  emit(1)
  withContext(Dispatchers.IO){
    emit(2)
  }
}

文中提到在 flow {...} 中「不能随意切换调度器,这是因为 emit 函数不是线程安全的」。这个描述似乎不太准确:

flow 块里的代码是顺序执行的,所以两次 emit 之间似乎没有线程安全问题。

flow 这里抛出异常是为了 context preservation,限制的是不能在不同的 CoroutineContextemit

所以这样其实是可以的:

flow {
  emit(1)
  val value = withContext(Dispatchers.IO) {
    2
  }
  emit(value)
}.collect {
  println(it)
}
bennyhuo commented 3 years ago

首先感谢支持~

flow  部分在我写书的时候还是实验状态,现在已经改了不少。你提到的这个点也是当时官当文档给出的,主要是内部状态的安全性问题,不是咱们自己传入的。

当然现在的新版是不是这样,还得看具体改成什么样了,我还没有跟进。等后面有空再确认一下

--------------原始邮件-------------- 发件人:"Jinyan Yu "<notifications@github.com>; 发送时间:2021年1月23日(星期六) 下午2:11 收件人:"enbandari/Bennyhuo" <Bennyhuo@noreply.github.com>; 抄送:"Bennyhuo "<bennyhuo@kotliner.cn>;"Author "<author@noreply.github.com>; 主题:Re: [enbandari/Bennyhuo] 破解 Kotlin 协程(11) - Flow 篇 | Bennyhuo (#33)

关于代码清单 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.

bennyhuo commented 3 years ago

关于代码清单 15:

flow { // BAD!!
  emit(1)
  withContext(Dispatchers.IO){
    emit(2)
  }
}

文中提到在 flow {...} 中「不能随意切换调度器,这是因为 emit 函数不是线程安全的」。这个描述似乎不太准确:

flow 块里的代码是顺序执行的,所以两次 emit 之间似乎没有线程安全问题。

flow 这里抛出异常是为了 context preservation,限制的是不能在不同的 CoroutineContextemit

所以这样其实是可以的:

flow {
  emit(1)
  val value = withContext(Dispatchers.IO) {
    2
  }
  emit(value)
}.collect {
  println(it)
}

参考官方文档:wrong-emission-withcontext

yujinyan commented 3 years ago

我读了下文档里面的内容,上面写道

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 的要求。

bennyhuo commented 3 years ago

嗯,get到你的点了,不过看上去跟书里的内容也不矛盾