【问题标题】:How to let withTimeoutOrNull return null but finish code in the block如何让 withTimeoutOrNull 返回 null 但在块中完成代码
【发布时间】:2018-07-17 12:25:12
【问题描述】:

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

所以我的问题是如何让它在没有 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】:

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

    对于您的代码,您的意图是不同的。您的意图是等待 1 秒钟,而不限制您的 doSomeHardWork 代码。但是,您的代码的结构 并不反映您的意图。您已将整个块包装到 withTimeout 中并将 doSomeHardWork 放入其中,而您的意图只是为它做一个有时间限制的 wait。因此,如果您以代码结构与您的意图相匹配的方式重写代码,它将在没有任何警告的情况下工作:

    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 开头的协程将在等待超时后继续运行。这很容易导致资源泄漏,除非您采取措施限制并发运行的后台作业的数量。

    【讨论】:

      猜你喜欢
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      • 2021-09-06
      • 2021-08-30
      • 2015-05-05
      • 1970-01-01
      相关资源
      最近更新 更多