Kotlin协程的未来等待超时(无取消)

时间:2019-01-25 17:47:09

标签: kotlin kotlinx.coroutines

鉴于我们有一个CompletableFuture f,在kotlin可挂起的作用域中,我们可以调用f.await(),我们将挂起直到完成。

我在使用签名f.await(t)实现类似功能时遇到麻烦,该功能必须挂起最长t毫秒,或者如果将来在此期间内完成(以先发生的为准),则必须尽快返回。

这是我尝试过的。

/**
 * Suspend current method until future is done or specified duration expires,
 * whichever happens first without cancelling the future.
 * Returns true if its done, false otherwise.
 */
suspend fun <T> ListenableFuture<T>.await(duration: Long): Boolean {
   val future = this
   try {
      withTimeout(duration) {
         withContext(NonCancellable) { // this does not help either
            future.await() // i do not expect the future itself to be cancelled
         }
      }
   } catch (t: TimeoutCancellationException) {
      // we expected this
   } catch (e: Throwable) {
      e.printStackTrace()
   }

   return future.isDone

}

fun main(args: Array<String>) = runBlocking<Unit> {
   val future = GlobalScope.future {
      try {
         repeat(5) {
            println("computing")
            delay(500)
         }
         println("complete")
      } finally {
         withContext(NonCancellable) {
            println("cancelling")
            delay(500)
            println("cancelled")
         }
      }
   }

   for (i in 0..10) {
      if (future.await(2000)) {
         println("checking : done")
      } else {
         println("checking : not done")
      }
   }
}

我还需要类似的功能来完成工作。但是也许对此的解决方案也可以帮助我...

此输出为

computing
computing
computing
computing
checking : done
checking : done
checking : done
checking : done
cancelling
checking : done
checking : done
checking : done
checking : done
checking : done
checking : done
checking : done

2 个答案:

答案 0 :(得分:1)

我已经写了一些测试代码:

fun main(args: Array<String>) = runBlocking {
    val future = calculateAsync()
    val result = future.await(2000)
    println("result=$result")
}

suspend fun <T> CompletableFuture<T>.await(duration: Long): T? {
    val future = this
    var result: T? = null
    try {
        withTimeout(duration) {
            result = future.await()
        }
    } catch (t: TimeoutCancellationException) {
        println("timeout exception")
    } catch (e: Throwable) {
        e.printStackTrace()
    }

    return result
}

@Throws(InterruptedException::class)
fun calculateAsync(): CompletableFuture<String> {
    val completableFuture = CompletableFuture<String>()

    Executors.newCachedThreadPool().submit {
        Thread.sleep(3000)
        println("after sleep")
        completableFuture.complete("Completed")
    }

    return completableFuture
}

运行此代码后,我们将获得输出:

timeout exception
result=null
after sleep

我们看到扩展函数await返回null,因为我们将超时设置为2000毫秒,但是CompletableFuture在3000毫秒后完成。在这种情况下,CompletableFuture被取消(它的isCancelled属性返回true),但是我们在calculateAsync函数中运行的线程继续执行(我们在日志{{ 1}})。

如果在after sleep函数中将超时持续时间设置为4000毫秒future.await(4000),我们将看到下一个输出:

main

现在我们有了一些结果,因为after sleep result=Completed 的执行速度超过了4000毫秒。

答案 1 :(得分:0)

这是我想出的,我认为这不是一个好的解决方案,因为我很可能为相当原始的任务创建大量垃圾。


suspend fun <T> CompletableFuture<T>.await(duration: Millis): Boolean {
   val timeout = CompletableFuture<Unit>()

   GlobalScope.launch {
      delay(duration)
      timeout.complete(Unit)
   }

   val anyOfTwo = CompletableFuture.anyOf(this, timeout)
   anyOfTwo.await()
   return this.isDone
}


fun main() = runBlocking {
   val future = CompletableFuture<String>()

   GlobalScope.launch {
      delay(2000)
      println("setting the result (future now ${future.isDone})")
      future.complete("something")
   }

   while (future.isNotDone()) {
      println("waiting for the future to complete for the next 500ms")
      val isDone = future.await(500)

      if (isDone) {
         println("future is done")
         break
      } else {

         println("future not done")
      }
   }

   Unit
}

这将给出

的输出
waiting for the future to complete for the next 500ms
future not done
waiting for the future to complete for the next 500ms
future not done
waiting for the future to complete for the next 500ms
future not done
waiting for the future to complete for the next 500ms
setting the result (future now false)
future is done

这就是我们想要的...