带有超时的Kotlin协程 [英] Kotlin Coroutines with timeout

查看:179
本文介绍了带有超时的Kotlin协程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前正在编写一个应该运行一个块的测试函数,或者(当达到一定的超时时)抛出一个异常.

I'm currently writing a test-function which should run a block or (when a certain timeout is reached) throws an exception.

我在Kotlin中尝试使用Coroutines进行此操作,但最终使用了CoroutinesCompletableFuture的混合物:

I was trying this with Coroutines in Kotlin but ended up with a mixture of Coroutines and 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中该问题的预期方法.

This works, but I'm not sure if this is the intended way to solve that problem in kotlin.

我还尝试了其他方法:

runBlocking {
    withTimeout(maxTimeout) {
        block()
    }
}

但是,这似乎在block调用例如Thread.sleep(...)

But this seems not to work as soon as the block calls e.g. Thread.sleep(...)

CompletableFuture方法是走的路还是有更好的方法?

So is the CompletableFuture approach the way to go or is there a better one?

更新1 我要实现的目标:

异步集成测试代码(例如从RabbitMq接收数据)应按以下方式进行测试:

Async Integration-Test code (like receiving data from RabbitMq) should be tested somehow like this:

var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
    assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
    assertThat(nextQueue).hasSize(3)
}
...

推荐答案

withTimeout { ... }旨在在超时时取消正在进行的操作,只有在相关操作为时才有可能可以取消.

withTimeout { ... } is designed to cancel the ongoing operation on timeout, which is only possible if the operation in question is cancellable.

它与future.get(timeout, unit)一起使用的原因是因为它仅等待超时.它实际上并不会以任何方式取消或中止您的后台操作,该操作在超时后仍然继续执行.

The reason it works with future.get(timeout, unit) is because it only waits with timeout. It does not actually cancel or abort in any way your background operation which still continues to execute after timeout had elapsed.

如果您想用协同程序模仿类似的行为,那么您应该等待超时,像这样:

If you want to mimick similar behavior with coroutines, then you should wait with timeout, like this:

val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout

它正常工作,因为await是可取消的函数,您可以通过阅读

It works properly because await is a cancellable function which you can verify by reading its API documentation.

但是,如果您想在超时时实际取消正在进行的操作,则应该以异步且可取消的方式实现代码.取消是 cooperative ,因此,首先,您在代码中使用的基础库必须提供支持取消正在进行的操作的异步API.

However, if you want to actually cancel the ongoing operation on timeout, then then you should implement your code in asyncronous and cancellable way. Cancellation is cooperative, so, to start, the underlying library that you are using in your code has to provide asynchronous API that supports cancellation of ongoing operation.

您可以在深入探究协程关于如何将协程与异步库集成.

You can read more about cancellation and timeouts in the corresponding section of the coroutines guide and watch the KotlinConf's Deep Dive into Coroutines on how to integrate coroutines with asynchronous libraries.

这篇关于带有超时的Kotlin协程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆