如何让withTimeoutOrNull返回null但在块中完成代码

问题描述 投票:1回答:1

我需要我的代码运行一个块并在1秒后返回值以防超时,但让它完成工作。我设法实现了一些有效的东西,但IDE建议用async替换withContext(DefaultDispatcher),但它的工作方式不同。

所以我的问题是如何在没有IDE警告的情况下使其工作。我是Kotlin Coroutines的新手,所以我可能会在这里遗漏一些东西。

@Test
fun how_timeout_with_null_works() = runBlocking<Unit> {
    val time = measureTimeMillis {
        println("Start test")
        val result = withTimeoutOrNull(1, TimeUnit.SECONDS) {
            async { doSomeHardWork() }.await()
        }
        println("End test $result")
    }
    println("Time $time")
    delay(3000)
}

private suspend fun doSomeHardWork(): String {
    println("start hard work")
    Thread.sleep(2000)
    print("end hard work")
    return "[hard work done]"
}
kotlin-coroutines
1个回答
4
投票

IDE在这种情况下发出警告,因为async(ctx) { ... }.await()通常是一个错误,而withContext(ctx) { ... }通常更好地反映了代码作者的原始意图。

如果您的代码,您的意图是不同的。你的意图是等待1秒,而不限制你的doSomeHardWork代码。但是,代码的结构并不反映您的意图。你把整个街区包裹进了withTimeout并把doSomeHardWork放在里面,而你的意图只是限时等待它。因此,如果您以代码结构与您的意图相匹配的方式重写代码,它将在没有任何警告的情况下工作:

val work = async { doSomeHardWork() } // start work
val result = withTimeoutOrNull(1, TimeUnit.SECONDS) { work.await() } // wait with timeout

如果您不止一次需要这种代码模式,那么您可以为自己定义一个方便的扩展:

suspend fun <T> Deferred<T>.awaitWithTimeout(time: Long, unit: TimeUnit): T? =
    withTimeoutOrNull(time, unit) { await() }

然后编写反映您意图的更好的代码:

val result = async { doSomeHardWork() }.awaitWithTimeout(1, TimeUnit.SECONDS)

但要小心。这些以async开头的协程将在等待超时后继续运行。这很容易导致资源泄漏,除非您采取措施限制同时运行后台作业的数量。

© www.soinside.com 2019 - 2024. All rights reserved.