Kotlin 当您在协程范围内抛出异常时,协程范围是否可重用?
通过以下步骤,我在解决协同程序的错误处理方面遇到了问题,我将其缩小到本单元测试中:Kotlin 当您在协程范围内抛出异常时,协程范围是否可重用?,kotlin,error-handling,kotlin-coroutines,Kotlin,Error Handling,Kotlin Coroutines,通过以下步骤,我在解决协同程序的错误处理方面遇到了问题,我将其缩小到本单元测试中: 我创建了一个与任何调度器的协同路由作用域 我在异步块(甚至在嵌套的异步块)的这个范围内的任何地方抛出异常 我对返回的延迟值调用wait并处理异常 这一切都很好。但是,当我尝试使用相同的协同程序作用域来启动新的协同程序时,这总是在异常情况下完成,并且出现相同的异常 以下是测试: fun `when you throw an exception in a coroutine scope, is the corouti
fun `when you throw an exception in a coroutine scope, is the coroutine scope dead?`() {
val parentJob = Job()
val coroutineScope = CoroutineScope(parentJob + Dispatchers.Default)
val deferredResult = coroutineScope.async { throw IllegalStateException() }
runBlocking {
try {
deferredResult.await()
} catch (e: IllegalStateException) {
println("We caught the exception. Good.")
}
try {
coroutineScope.async { println("we can still use the scope") }.await()
} catch (e: IllegalStateException) {
println("Why is this same exception still being thrown?")
}
}
}
We caught the exception. Good.
Why is this same exception still being thrown?
fun `when you throw an exception in a coroutine scope, is the coroutine scope dead?`() {
val parentJob = Job()
val coroutineScope = CoroutineScope(parentJob + Dispatchers.Default)
val deferredResult = coroutineScope.async { throw IllegalStateException() }
runBlocking {
try {
deferredResult.await()
} catch (e: IllegalStateException) {
println("We caught the exception. Good.")
}
try {
coroutineScope.async { println("we can still use the scope") }.await()
} catch (e: IllegalStateException) {
println("Why is this same exception still being thrown?")
}
}
}
We caught the exception. Good.
Why is this same exception still being thrown?
- 为什么会发生这种情况?
- 我的理解是,您可以正常地处理异常,并使用协程从中恢复
- 我应该如何处理异常?
- 我需要创建一个新的合作计划吗李>
- 如果我想继续使用同一个coroutineScope,我是否可以从不抛出异常
- 我是否应该返回
或
李>
- 我尝试过使用CoroutineExceptionHandler,但仍然得到相同的结果
注意:我使用的是Kotlin 1.3,当您在一个作用域中启动一个协同程序(使用
async
或launch
)时,默认情况下,协同程序失败将取消该作用域,以立即取消所有其他子项。这种设计避免了悬空和丢失异常
这里的一般建议是:
- 除非确实需要并发,否则不要使用
/async
。当您使用挂起函数设计代码时,不需要太多地使用wait
和async
wait
- 如果确实需要并发执行,请遵循以下模式:
coroutineScope { val d1 = async { doOne() } val d2 = async { doTwo() } ... // retrieve and process results process(d1.await(), d2.await(), .... ) }
try{…}catch{…}
放在coroutineScope{…}
周围,以捕获任何并发执行操作中的失败
- 还有其他高级机制(如
)允许细粒度异常处理。您可以在文档中阅读更多内容SupervisorJob
parentJob
。为了完全确定,如果我使用try/catch将调用包装到一个挂起函数,从而捕获一个异常,它会取消作用域和其他子项吗?换句话说,捕获的异常在父协同程序取消方面是否与未捕获的不同?