协程没有完成,因为它有一个与之关联的异步未完成,如何 运行 独立异步?
Coroutine does not finish because it has an async associated with it that did not finish, how to run async independently?
我只是在玩协程,只是注意到了一个小的不便或者更确切地说是一个很棒的功能。但以下代码永远不会完成:
val job = GlobalScope.launch {
doSomeWork()
async {
while(true) { //if removed job.join finishes in 60 seconds
delay(60000L)
doRecurringWork()
}
}
}
runBlocking {
job.join()
}
似乎 job
完成了,但 job.join
等待 async
完成,这本来是不会发生的。
有什么方法可以取消 async
操作与当前协程的链接吗? (运行 另一个工作解决了这个问题,但避免了这个问题)
这里有一些更详细的代码:
val tag="tag"
Log.d(tag,"in main before launch")
val job = GlobalScope.launch {
Log.d(tag,"in GlobalScope before doSomeWork")
doSomeWork()
Log.d(tag,"in GlobalScope after doSomeWork before async")
async {
Log.d(tag,"in async before while")
while(true) { //if removed job.join finishes in 60 seconds
delay(60000L)
doRecurringWork()
Log.d(tag,"in async after doRecurringWork")
}
Log.d(tag,"in async after while (die)")
}
Log.d(tag,"in GlobalScope after async (die)")
}
Log.d(tag,"in main after launch before runBlocking")
runBlocking {
Log.d(tag,"in runBlocking before join")
job.join()
Log.d(tag,"in runBlocking after join (die)")
}
Log.d(tag,"in main after runBlocking (die)")
//log:
//in main before launch
//in main after launch before runBlocking
//in runBlocking before join
//in GlobalScope before doSomeWork
//in GlobalScope after doSomeWork before async
//in async before while
//in GlobalScope after async (die)
//in async after doRecurringWork
//in async after doRecurringWork
//in async after doRecurringWork
注意:我把代码调高了一点,人们回避问题并专注于技术细节。
runBlocking
阻塞主线程,然后 async
块内的 withContext(Dispatchers.Main)
尝试在已经阻塞的主线程上执行代码块,导致死锁。如果您将调度程序从 Main
更改为 IO
,那么您的代码将起作用(但它无法访问 UI)。
可以将 runBlocking
用于学习和探索的目的,但不应将其用于其他目的,因为它会破坏协程的全部目的。
Is there any way to unlink an async operation from the current
coroutine?
一个coroutine
和它的child人之间存在parentchild关系,parentJob
只有当所有其child仁已毕。因此,您无法说“考虑 parent 作业已完成,而 child 异步操作仍在 运行'
见docs
作业是分层排列的。您的 async
工作是您 launch
工作的 child,并且 parent 在其 children 完成之前无法完成。
这与“结构化并发”背后的整个想法很接近——当您的作业完成时,您知道它实际上已经完成,包括它的所有异步子任务。
如果你想做其他语言做的事情,那么你可以使用 GlobalScope.async
而不是 async
。然后你的 parent 工作可以提前 return,完全忘记 async
工作,因为它是兄弟而不是 child。该工作可以 运行 永远,无缘无故地默默消耗资源。
如果您不希望 async
工作永远 运行,那么您应该将其保留为 child 工作,并且在您不想要时取消它再等等。
我只是在玩协程,只是注意到了一个小的不便或者更确切地说是一个很棒的功能。但以下代码永远不会完成:
val job = GlobalScope.launch {
doSomeWork()
async {
while(true) { //if removed job.join finishes in 60 seconds
delay(60000L)
doRecurringWork()
}
}
}
runBlocking {
job.join()
}
似乎 job
完成了,但 job.join
等待 async
完成,这本来是不会发生的。
有什么方法可以取消 async
操作与当前协程的链接吗? (运行 另一个工作解决了这个问题,但避免了这个问题)
这里有一些更详细的代码:
val tag="tag"
Log.d(tag,"in main before launch")
val job = GlobalScope.launch {
Log.d(tag,"in GlobalScope before doSomeWork")
doSomeWork()
Log.d(tag,"in GlobalScope after doSomeWork before async")
async {
Log.d(tag,"in async before while")
while(true) { //if removed job.join finishes in 60 seconds
delay(60000L)
doRecurringWork()
Log.d(tag,"in async after doRecurringWork")
}
Log.d(tag,"in async after while (die)")
}
Log.d(tag,"in GlobalScope after async (die)")
}
Log.d(tag,"in main after launch before runBlocking")
runBlocking {
Log.d(tag,"in runBlocking before join")
job.join()
Log.d(tag,"in runBlocking after join (die)")
}
Log.d(tag,"in main after runBlocking (die)")
//log:
//in main before launch
//in main after launch before runBlocking
//in runBlocking before join
//in GlobalScope before doSomeWork
//in GlobalScope after doSomeWork before async
//in async before while
//in GlobalScope after async (die)
//in async after doRecurringWork
//in async after doRecurringWork
//in async after doRecurringWork
注意:我把代码调高了一点,人们回避问题并专注于技术细节。
runBlocking
阻塞主线程,然后 async
块内的 withContext(Dispatchers.Main)
尝试在已经阻塞的主线程上执行代码块,导致死锁。如果您将调度程序从 Main
更改为 IO
,那么您的代码将起作用(但它无法访问 UI)。
可以将 runBlocking
用于学习和探索的目的,但不应将其用于其他目的,因为它会破坏协程的全部目的。
Is there any way to unlink an async operation from the current coroutine?
一个coroutine
和它的child人之间存在parentchild关系,parentJob
只有当所有其child仁已毕。因此,您无法说“考虑 parent 作业已完成,而 child 异步操作仍在 运行'
见docs
作业是分层排列的。您的 async
工作是您 launch
工作的 child,并且 parent 在其 children 完成之前无法完成。
这与“结构化并发”背后的整个想法很接近——当您的作业完成时,您知道它实际上已经完成,包括它的所有异步子任务。
如果你想做其他语言做的事情,那么你可以使用 GlobalScope.async
而不是 async
。然后你的 parent 工作可以提前 return,完全忘记 async
工作,因为它是兄弟而不是 child。该工作可以 运行 永远,无缘无故地默默消耗资源。
如果您不希望 async
工作永远 运行,那么您应该将其保留为 child 工作,并且在您不想要时取消它再等等。