Any*_*ker 19 kotlin kotlin-coroutines
我正在尝试创建一个对象,它可以在自己的线程中顺序执行一些任务,就像它是一个队列一样。
以下示例仅用于演示我的设置,可能完全错误。
class CoroutinesTest {
fun a() {
GlobalScope.launch {
println("a started")
delay(1000)
println("a completed")
}
}
fun b() {
GlobalScope.launch {
println("b started")
delay(2000)
println("b completed")
}
}
fun complex() {
a()
b()
}
}
fun main() {
runBlocking {
val coroutinesTest = CoroutinesTest()
coroutinesTest.complex()
delay(10000)
}
}
Run Code Online (Sandbox Code Playgroud)
现在这段代码打印以下内容
a started
b started
a completed
b completed
Run Code Online (Sandbox Code Playgroud)
这意味着a
和b
并行执行。方法a
,b
和complex
可以从不同的线程调用。当然,该complex
方法也应该支持这个概念。现在,我需要一种机制,允许我一次只执行一个任务,这样我就可以获得以下输出:
a started
a completed
b started
b completed
Run Code Online (Sandbox Code Playgroud)
我做了一些研究,认为actor
使用 aChannel
可以做所需的事情,但actor
现在被标记为过时(问题#87)。我不喜欢使用可能发生变化的 API 的想法,所以我想以通用的方式来做这件事。
Tyl*_*r V 26
TL;DR有几个选项可用于控制顺序协程。
Channel
使它们按照调用的顺序一次运行一个Mutex
使它们一次运行一个,但不保证顺序Flow
(如BigSt下面的答案中所述)使它们按照调用的顺序一次运行一个,但是请确保流缓冲区足够大,否则如果“正在运行”的作业数量超过 1,则作业可能会丢失大于缓冲区大小。控制执行顺序的一种方法是使用Channel - 将延迟执行的协程作业传递到通道以按顺序运行。与互斥锁不同,通道保证作业按照启动的顺序运行。
class CoroutinesTest {
private val channel = Channel<Job>(capacity = Channel.UNLIMITED).apply {
GlobalScope.launch {
consumeEach { it.join() }
}
}
fun a() {
channel.trySend(
GlobalScope.launch(start = CoroutineStart.LAZY) {
println("a started")
delay(1000)
println("a completed")
}
)
}
fun b() {
channel.trySend(
GlobalScope.launch(start = CoroutineStart.LAZY) {
println("b started")
delay(2000)
println("b completed")
}
)
}
fun complex() {
// add two separate jobs to the channel,
// this will run a, then b
a()
b()
}
}
Run Code Online (Sandbox Code Playgroud)
调用complex
总是会产生:
a started
a completed
b started
b completed
Run Code Online (Sandbox Code Playgroud)
Mutex
您可以使用and调用来阻止作业同时运行withLock
。如果您在短时间内连续拨打大量电话,则无法保证电话顺序。例如:
class CoroutinesTest {
private val lock = Mutex()
fun a() {
GlobalScope.launch {
lock.withLock {
println("a started")
delay(1000)
println("a completed")
}
}
}
fun b() {
GlobalScope.launch {
lock.withLock {
println("b started")
delay(2000)
println("b completed")
}
}
}
fun complex() {
a()
b()
}
}
Run Code Online (Sandbox Code Playgroud)
调用complex
可以产生:
a started
a completed
b started
b completed
Run Code Online (Sandbox Code Playgroud)
或者:
b started
b completed
a started
a completed
Run Code Online (Sandbox Code Playgroud)
如果您必须始终运行a
,那么b
您可以使它们都挂起函数并从单个范围内调用它们(仅允许调用complex
,不允许单独a
调用b
)。在这种情况下,complex
调用确实保证a
在starting之前运行并完成b
。
class CoroutinesTest {
suspend fun aImpl() {
println("a started")
delay(1000)
println("a completed")
}
suspend fun bImpl() {
println("b started")
delay(2000)
println("b completed")
}
fun complex() {
GlobalScope.launch {
aImpl()
bImpl()
}
}
}
Run Code Online (Sandbox Code Playgroud)
调用complex
总是会产生:
a started
a completed
b started
b completed
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10097 次 |
最近记录: |