【发布时间】:2019-10-11 18:55:32
【问题描述】:
我正在使用 withContext 将函数转换为不会阻塞调用线程的挂起函数。 为此,我使用了https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761 作为参考。
现在我想用超时调用这个函数。为此,我使用 withTimeout 来调用函数:
@Test
internal fun timeout() {
runBlocking {
logger.info("launching")
try {
withTimeout(1000) {
execute()
}
} catch (e: TimeoutCancellationException) {
logger.info("timed out", e)
}
}
}
private suspend fun execute() {
withContext(Dispatchers.IO) {
logger.info("sleeping")
Thread.sleep(2000)
}
}
所以我希望在 1000 毫秒后取消异步启动的协程并抛出 TimeoutCancellationException。
但是会发生什么是完整的 2000 毫秒通过,当协程完成时抛出异常:
14:46:29.231 [main @coroutine#1] 信息 b.t.c.c.CoroutineControllerTest - 发射
14:46:29.250 [DefaultDispatcher-worker-1 @coroutine#1] 信息 b.t.c.c.CoroutineControllerTest - 睡眠
14:46:31.261 [main@coroutine#1] 信息 b.t.c.c.CoroutineControllerTest - 超时 kotlinx.coroutines.TimeoutCancellationException:等待超时 1000 毫秒 kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:128) 在 kotlinx.coroutines.TimeoutCoroutine.run(Timeout.kt:94) 在 kotlinx.coroutines.EventLoopImplBase$DelayedRunnableTask.run(EventLoop.kt:307) 在 kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.kt:116) 在 kotlinx.coroutines.DefaultExecutor.run(DefaultExecutor.kt:68) 在 java.lang.Thread.run(Thread.java:748)
我用错了吗?
或者这可能是预期的行为?在文档中,计数器也变为 2,这意味着在取消协程之前已经过去了 1500 毫秒: https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/cancellation-and-timeouts.md#timeout
【问题讨论】:
-
Thread.sleep阻塞当前线程(与delay函数不同)并且无法取消(仅在Thread类文档的意义上被中断或停止)。 -
只要打电话给
Thread.currentThread().interrupt(),你就可以找到TimeoutCancellationException。这将导致runBlocking以InterruptedException退出(但实际上不会取消操作)。