如何顺序运行Kotlin Coroutines?
我有一个coroutinescope
和log()
函数的实例,该函数看起来如下:
private val scope = CoroutineScope(Dispatchers.IO)
fun log(message: String) = scope.launch { // launching a coroutine
println("$message")
TimeUnit.MILLISECONDS.sleep(100) // some blocking operation
}
我使用此测试代码启动Coroutines:
repeat(5) { item ->
log("Log $item")
}
log()函数可以从任何位置,在任何
thread
中都从任何位置调用,但不能从coroutine中调用。
经过几次测试后,我可以看到如下的顺序结果:
Log 0
Log 2
Log 4
Log 1
Log 3
打印日志的顺序可能不同。如果我正确理解coroutines的执行不能保证是顺序的。这意味着可以在项目0
的Coroutine之前启动项目2
的Coroutine。
我希望为每个项目依次启动Coroutines,并且“某些阻止操作”将依次执行,以始终实现下一个日志:
Log 0
Log 1
Log 2
Log 3
Log 4
有没有办法使启动Coroutines顺序?也许还有其他方法可以实现我想要的东西?
在此先感谢您的任何帮助!
I have an instance of CoroutineScope
and log()
function which look like the following:
private val scope = CoroutineScope(Dispatchers.IO)
fun log(message: String) = scope.launch { // launching a coroutine
println("$message")
TimeUnit.MILLISECONDS.sleep(100) // some blocking operation
}
And I use this test code to launch coroutines:
repeat(5) { item ->
log("Log $item")
}
The log()
function can be called from any place, in any Thread
, but not from a coroutine.
After a couple of tests I can see not sequential result like the following:
Log 0
Log 2
Log 4
Log 1
Log 3
There can be different order of printed logs. If I understand correctly the execution of coroutines doesn't guarantee to be sequential. What it means is that a coroutine for item 2
can be launched before the coroutine for item 0
.
I want that coroutines were launched sequentially for each item and "some blocking operation" would execute sequentially, to always achieve next logs:
Log 0
Log 1
Log 2
Log 3
Log 4
Is there a way to make launching coroutines sequential? Or maybe there are other ways to achieve what I want?
Thanks in advance for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一种可能的策略是使用渠道按顺序加入启动的作业。您需要懒洋洋地启动工作,以便在
加入
之前不会启动。Trysend
在频道具有无限容量时始终成功。您需要使用trysend
,因此可以从Coroutine外部调用。One possible strategy is to use a Channel to join the launched jobs in order. You need to launch the jobs lazily so they don't start until
join
is called on them.trySend
always succeeds when the Channel has unlimited capacity. You need to usetrySend
so it can be called from outside a coroutine.因为
是顺序我们可以使用flow
flowmutableSharedFlow
依次收集和处理数据:它始终以正确的顺序打印日志:
它适用于所有情况,但是需要确保设置了足够的元素以
replay
和extrabufferCapacity
mutableSharedFlow的参数
处理所有项目。另一种方法是
使用
dispatchers.io.limitedParallelism(1)
作为coroutinescope
的上下文。如果Coroutines不包含暂停
功能的调用,并从相同的 thread ,例如主线程,它使得它们依次运行。因此,此解决方案仅与阻止(非代码>悬挂)操作启动>启动
coroutine builder:事实证明,单线程调度程序是FIFO执行者。因此,将
coroutinescope
执行到一个线程解决问题。Since
Flow
s are sequential we can useMutableSharedFlow
to collect and handle data sequentially:It always prints the logs in the correct order:
It works for all cases, but need to be sure there are enough elements set to
replay
andextraBufferCapacity
parameters ofMutableSharedFlow
to handle all items.Another approach is
Using
Dispatchers.IO.limitedParallelism(1)
as a context for theCoroutineScope
. It makes coroutines run sequentially if they don't contain calls tosuspend
functions and launched from the same Thread, e.g. Main Thread. So this solution works only with blocking (notsuspend
) operation insidelaunch
coroutine builder:It turns out that the single thread dispatcher is a FIFO executor. So limiting the
CoroutineScope
execution to one thread solves the problem.