具有超时功能的 Kotlin 协程

标签 kotlin kotlin-coroutines

我目前正在编写一个测试函数,它应该运行一个 block 或(当达到某个超时时)抛出异常。

我在 Kotlin 中尝试使用 Coroutines,但最终得到了 CoroutinesCompletableFuture 的混合:

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 的相应部分中阅读有关取消和超时的更多信息。并观看 KotlinConf 的 Deep Dive into Coroutines关于如何将协程与异步库集成。

关于具有超时功能的 Kotlin 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47635367/

相关文章:

kotlin - 给定范围内的安全异步

java - 将 List 放入 Bundle 对象

android - Unresolved reference @HiltAndroidApp 或 Android 中的任何其他 Hilt 注释

java - 将 Java 按位 "and"运算符转换为 Kotlin

multithreading - 使用多线程协程有什么好处?

spring-boot - 如果 Mono 为空,则创建一个未找到的 ServerResponse

android - 如何使用 mockk 模拟 Build.VERSION.SDK_INT

android - JUnit测试返回lateinit属性<nameOfInstance>尚未在演示者上初始化

java - Kotlin Flows Java 互操作回调

java - 尝试为 `coroutine`编写 `handler`模拟,但不起作用