Kotlin协程,启动如何处理异常

时间:2019-07-13 18:59:58

标签: exception kotlin kotlin-coroutines

fun main(args: Array<String>) {
runBlocking {

        withTimeout(1300L) {
            repeat(1000) { i ->
                    println("I'm sleeping $i ...")
                delay(500L)
            }
        }

}
}

它崩溃,但异常:

I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms
 at kotlinx.coroutines.TimeoutKt.TimeoutCancellationException (Timeout.kt:128) 
 at kotlinx.coroutines.TimeoutCoroutine.run (Timeout.kt:94) 
 at kotlinx.coroutines.EventLoopImplBase$DelayedRunnableTask.run (EventLoop.kt:307) 
 at kotlinx.coroutines.EventLoopImplBase.processNextEvent (EventLoop.kt:116) 
 at kotlinx.coroutines.DefaultExecutor.run (DefaultExecutor.kt:68) 
 at java.lang.Thread.run (Thread.java:745)

但该块位于launch

fun main(args: Array<String>) {
runBlocking {
    launch {//<===
        withTimeout(1300L) {
            repeat(1000) { i ->
                    println("I'm sleeping $i ...")
                delay(500L)
            }
        }
    }//<===
}
}

那么超时也没有例外:

I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...

为什么启动没有例外?

2 个答案:

答案 0 :(得分:1)

TimeoutCancellationExceptionCancellationException的子类。 抛出launch的协程中引发的CancellationException不会传播给任何异常处理程序,CoroutineExceptionHandler以及线程的Uncaught Exception Handler(在您的第一个示例中最后一个调用了)。 >

这是第二个示例的修改版本,其中CancellationException被包装在普通的RuntimeException中(不是CancellationException的东西)。您将再次看到stacktrace日志:

import kotlinx.coroutines.*

fun main(args: Array<String>) {
    runBlocking {
        launch {
            try {
                withTimeout(1300L) {
                    repeat(1000) { i ->
                        println("I'm sleeping $i ...")
                        delay(500L)
                    }
                }
            } catch (t: CancellationException) { 
                throw RuntimeException(t)
            }
        }
    }
}

为什么启动和运行块工作不同的主要原因是因为运行块应该返回值,但是因为作用域被取消了,没有东西要返回,并且抛出了取消异常,对于启动它只是取消了协程

在这里您可以找到有关协程和异常的更多信息: https://link.medium.com/HEhVwUxOkY

答案 1 :(得分:0)

Cancellation is tightly bound with exceptions. Coroutines internally use CancellationException for cancellation, these exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can be obtained by catch block.

launch构建器将忽略TimeoutCancellationException

The TimeoutCancellationException that is thrown by withTimeout is a subclass of CancellationException. We have not seen its stack trace printed on the console before. That is because inside a cancelled coroutine CancellationException is considered to be a normal reason for coroutine completion. However, in this example we have used withTimeout right inside the main function.