带超时的 Kotlin 协程
Kotlin Coroutines with timeout
我目前正在编写一个测试函数,它应该 运行 一个块或者(当达到某个超时时)抛出一个异常。
我在 Kotlin 中用 Coroutines
尝试过这个,但最终混合了 Coroutines
和 CompletableFuture
:
fun <T> runBlockWithTimeout(maxTimeout: Long, block: () -> T ): T {
val future = CompletableFuture<T>()
// runs the coroutine
launch { block() }
return future.get(maxTimeout, TimeUnit.MILLISECONDS)
}
这可行,但我不确定这是否是在 kotlin 中解决该问题的预期方法。
我也试过其他方法:
runBlocking {
withTimeout(maxTimeout) {
block()
}
}
但这似乎不会在 block
调用时立即起作用,例如Thread.sleep(...)
那么 CompletableFuture
方法是正确的方法还是有更好的方法?
更新 1
我想达到的目标:
异步集成测试代码(比如从 RabbitMq 接收数据)应该像这样测试:
var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
assertThat(nextQueue).hasSize(3)
}
...
withTimeout { ... }
旨在 取消 正在进行的超时操作,只有当相关操作 可取消.
它与 future.get(timeout, unit)
一起工作的原因是因为它只 等待 超时。它实际上不会以任何方式取消或中止您的后台操作,该操作在超时后仍继续执行。
如果你想用协同程序模仿类似的行为,那么你应该等待超时,像这样:
val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout
它工作正常,因为 await
是一个可取消的函数,您可以通过阅读 its API documentation.
来验证
但是,如果你真的想在超时时取消正在进行的操作,那么你应该以异步和可取消的方式实现你的代码。取消是 合作 ,因此,首先,您在代码中使用的基础库必须提供支持取消正在进行的操作的异步 API。
您可以在有关如何将协程与异步库集成的 coroutines guide and watch the KotlinConf's Deep Dive into Coroutines 的相应部分阅读有关取消和超时的更多信息。
我目前正在编写一个测试函数,它应该 运行 一个块或者(当达到某个超时时)抛出一个异常。
我在 Kotlin 中用 Coroutines
尝试过这个,但最终混合了 Coroutines
和 CompletableFuture
:
fun <T> runBlockWithTimeout(maxTimeout: Long, block: () -> T ): T {
val future = CompletableFuture<T>()
// runs the coroutine
launch { block() }
return future.get(maxTimeout, TimeUnit.MILLISECONDS)
}
这可行,但我不确定这是否是在 kotlin 中解决该问题的预期方法。
我也试过其他方法:
runBlocking {
withTimeout(maxTimeout) {
block()
}
}
但这似乎不会在 block
调用时立即起作用,例如Thread.sleep(...)
那么 CompletableFuture
方法是正确的方法还是有更好的方法?
更新 1 我想达到的目标:
异步集成测试代码(比如从 RabbitMq 接收数据)应该像这样测试:
var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
assertThat(nextQueue).hasSize(3)
}
...
withTimeout { ... }
旨在 取消 正在进行的超时操作,只有当相关操作 可取消.
它与 future.get(timeout, unit)
一起工作的原因是因为它只 等待 超时。它实际上不会以任何方式取消或中止您的后台操作,该操作在超时后仍继续执行。
如果你想用协同程序模仿类似的行为,那么你应该等待超时,像这样:
val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout
它工作正常,因为 await
是一个可取消的函数,您可以通过阅读 its API documentation.
但是,如果你真的想在超时时取消正在进行的操作,那么你应该以异步和可取消的方式实现你的代码。取消是 合作 ,因此,首先,您在代码中使用的基础库必须提供支持取消正在进行的操作的异步 API。
您可以在有关如何将协程与异步库集成的 coroutines guide and watch the KotlinConf's Deep Dive into Coroutines 的相应部分阅读有关取消和超时的更多信息。