Kotlin协程无法处理异常 [英] Kotlin coroutine can't handle exception
问题描述
我在和协程一起玩耍,发现一些非常奇怪的行为.我想使用suspendCoroutine()
在我的项目中转换一些异步请求.这是显示此问题的代码.
I was playing around with coroutines and found some very strange behavior. I want to convert some asynchronous requests in my project using suspendCoroutine()
. Here's piece of code showing this problem.
在第一种情况下,当在runBlocking
协程中调用suspend函数时,来自延续的异常进入catch块,然后runBlocking
成功完成.但是在第二种情况下,当创建新的async
协程时,异常会通过catch块并使整个程序崩溃.
In first case, when suspend function is being called in runBlocking
coroutine, exception from continuation goes to catch block, and then runBlocking
finishes successfully. But in second case, when creating new async
coroutine, exception goes through catch block and crashes the whole program.
package com.example.lib
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
object Test {
fun runSuccessfulCoroutine() {
runBlocking {
try {
Repository.fail()
} catch (ex: Throwable) {
println("Catching ex in runSuccessfulCoroutine(): $ex")
}
}
}
fun runFailingCoroutine() {
runBlocking {
try {
async { Repository.fail() }.await()
} catch (ex: Throwable) {
println("Catching ex in runFailingCoroutine(): $ex")
}
}
}
}
object Repository {
suspend fun fail(): Int = suspendCoroutine { cont ->
cont.resumeWithException(RuntimeException("Exception at ${Thread.currentThread().name}"))
}
}
fun main() {
Test.runSuccessfulCoroutine()
println()
Test.runFailingCoroutine()
println("We will never get here")
}
这就是控制台上显示的内容:
That's what is printed on console:
Catching ex in runSuccessfulCoroutine(): java.lang.RuntimeException: Exception at main
Catching ex in runFailingCoroutine(): java.lang.RuntimeException: Exception at main
Exception in thread "main" java.lang.RuntimeException: Exception at main
at com.example.lib.Repository.fail(MyClass.kt:32)
at com.example.lib.Test$runFailingCoroutine$1$1.invokeSuspend(MyClass.kt:22)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:236)
at kotlinx.coroutines.EventLoopBase.processNextEvent(EventLoop.kt:123)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:69)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:45)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:35)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at com.example.lib.Test.runFailingCoroutine(MyClass.kt:20)
at com.example.lib.MyClassKt.main(MyClass.kt:41)
at com.example.lib.MyClassKt.main(MyClass.kt)
Process finished with exit code 1
关于发生这种情况的任何想法-是bug,还是我以错误的方式使用协同程序?
Any ideas why this is happening - is it a bug, or am i using coroutines the wrong way?
更新:
使用coroutineScope { ... }
将减轻runFailingCoroutine()
fun runFailingCoroutine() = runBlocking {
try {
coroutineScope { async { fail() }.await() }
} catch (ex: Throwable) {
println("Catching ex in runFailingCoroutine(): $ex")
}
}
推荐答案
第二个示例的行为是正确的,这是结构化并发的工作.
由于内部async
块引发异常,因此该协程被取消.由于结构性并发,父作业也被取消.
The behavior of your second example is correct, this is the work of structured concurrency.
Because the inner async
block throws an exception, this coroutine is cancelled. Due to structured concurrency the parent job is cancelled as well.
看看这个小例子:
val result = coroutineScope {
async {
throw IllegalStateException()
}
10
}
即使我们从不请求async
结果,该块也将永远不会返回值.内部协程被取消,外部范围也被取消.
This block will never return a value, even if we never request the async
result. The inner coroutine is cancelled and the outer scope is cancelled as well.
如果您不喜欢这种行为,可以使用supervisorScope
.在这种情况下,内部协程可能会失败,而外部协程不会失败.
If you don't like this behavior you can use the supervisorScope
. In this case the inner coroutine can fail without failing the outer coroutine.
val result = supervisorScope {
async {
throw IllegalStateException()
}
10
}
在第一个示例中,您在协程块内捕获了异常,因此,协程正常退出.
In your first example you catch the exception inside of the coroutine block, because of this, the coroutine exits normally.
有关此主题的讨论,请参见:
For discussion of this topic see:
- https://github.com/Kotlin/kotlinx.coroutines/issues/552
- https://github.com/Kotlin/kotlinx.coroutines/issues/763
- https://github.com/Kotlin/kotlinx.coroutines/issues/552
- https://github.com/Kotlin/kotlinx.coroutines/issues/763
这篇关于Kotlin协程无法处理异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!