9.7 设置协程超时时间

我们通常取消协同执行的原因给协程的执行时间设定一个执行时间上限。我们也可以使用 withTimeout 函数来给一个协程任务的执行设定最大执行时间,超出这个时间,就直接终止掉。代码示例如下:

  1. fun testTimeouts() = runBlocking {
  2. withTimeout(3000L) {
  3. repeat(100) { i ->
  4. println("I'm sleeping $i ...")
  5. delay(500L)
  6. }
  7. }
  8. }

运行上述代码,我们将会看到如下输出:

  1. I'm sleeping 0 ...
  2. I'm sleeping 1 ...
  3. I'm sleeping 2 ...
  4. I'm sleeping 3 ...
  5. I'm sleeping 4 ...
  6. I'm sleeping 5 ...
  7. Exception in thread "main" kotlinx.coroutines.experimental.TimeoutException: Timed out waiting for 3000 MILLISECONDS
  8. at kotlinx.coroutines.experimental.TimeoutExceptionCoroutine.run(Scheduled.kt:110)
  9. at kotlinx.coroutines.experimental.EventLoopImpl$DelayedRunnableTask.invoke(EventLoop.kt:199)
  10. at kotlinx.coroutines.experimental.EventLoopImpl$DelayedRunnableTask.invoke(EventLoop.kt:195)
  11. at kotlinx.coroutines.experimental.EventLoopImpl.processNextEvent(EventLoop.kt:111)
  12. at kotlinx.coroutines.experimental.BlockingCoroutine.joinBlocking(Builders.kt:205)
  13. at kotlinx.coroutines.experimental.BuildersKt.runBlocking(Builders.kt:150)
  14. at kotlinx.coroutines.experimental.BuildersKt.runBlocking$default(Builders.kt:142)
  15. at com.easy.kotlin.CancellingCoroutineDemo.testTimeouts(CancellingCoroutineDemo.kt:169)
  16. at com.easy.kotlin.CancellingCoroutineDemoKt.main(CancellingCoroutineDemo.kt:193)

由 withTimeout 抛出的 TimeoutException 是 CancellationException 的一个子类。这个TimeoutException类型定义如下:

  1. private class TimeoutException(
  2. time: Long,
  3. unit: TimeUnit,
  4. @JvmField val coroutine: Job
  5. ) : CancellationException("Timed out waiting for $time $unit")

如果您需要在超时时执行一些附加操作, 则可以把逻辑放在 try {…} catch (e: CancellationException) {…} 代码块中。例如:

  1. try {
  2. ccd.testTimeouts()
  3. } catch (e: CancellationException) {
  4. println("I am timed out!")
  5. }