【问题标题】:Kotlin Coroutines with timeout带有超时的 Kotlin 协程
【发布时间】:2018-05-18 00:53:00
【问题描述】:

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

我在 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)
}
...

【问题讨论】:

  • 如果你正在使用一些测试库,它可能已经有超时功能。例如,使用 JUnit,您可以在测试方法上设置 @Test(timeout=5000) 注释。
  • 我更新了描述,以便更好地理解我想要实现的目标。

标签: kotlin kotlin-coroutines


【解决方案1】:

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 了解如何将协程与异步库集成。

【讨论】:

  • Roman 是否有类似 d.await(timeout) 的东西,这样它不会取消而是从当前暂停的函数中唤醒,从而有机会检查某些内容,如果需要,请执行 d.cancel()...我希望 d 继续工作直到手动取消
  • 为此目的使用 withTimeout(timeout) { d.await() } - 它就是这样做的。超时后异步任务仍在工作。
  • 我相信这就是我试图做的,如果你有时间请看看我的尝试stackoverflow.com/questions/54370415/…
猜你喜欢
  • 2019-11-28
  • 2019-04-29
  • 2018-04-13
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 2022-01-07
相关资源
最近更新 更多