Vic*_*kiy 2 android asynchronous kotlin kotlin-coroutines
我有以下代码结构:
@Throws(InterruptedException::class)
fun method() {
// do some blocking operations like Thread.sleep(...)
}
var job = launch {
method()
}
job.cancelAndJoin()
Run Code Online (Sandbox Code Playgroud)
该method由外部库提供,我无法控制其行为。执行可能需要很多时间,因此在某些情况下应该通过超时取消。
我可以使用withTimeoutkotlin协程库提供的功能,但是由于协程设计,它无法取消带有阻塞的代码。它有一些解决方法吗?
主要思想是将协程外上下文线程池与可以在旧样式中中断的 JVM 线程一起使用,并从协程执行中订阅取消事件。当事件被 捕获时invokeOnCancellation,我们可以中断当前线程。
实施:
val externalThreadPool = Executors.newCachedThreadPool()
suspend fun <T> withTimeoutOrInterrupt(timeMillis: Long, block: () -> T) {
withTimeout(timeMillis) {
suspendCancellableCoroutine<Unit> { cont ->
val future = externalThreadPool.submit {
try {
block()
cont.resumeWith(Result.success(Unit))
} catch (e: InterruptedException) {
cont.resumeWithException(CancellationException())
} catch (e: Throwable) {
cont.resumeWithException(e);
}
}
cont.invokeOnCancellation {
future.cancel(true)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它提供了与通常类似的行为withTimeout,但它还支持运行带有阻塞的代码。
注意:只有当您知道内部代码使用阻塞并且可以正确处理抛出的InterruptedException. 在大多数情况下,该withTimeout功能是首选。
更新:从协程版本 1.3.7 开始,有一个新函数runInterruptible,它提供了相同的行为。所以这段代码可以简化:
suspend fun <T> withTimeoutOrInterrupt(timeMillis: Long, block: () -> T) {
withTimeout(timeMillis) {
runInterruptible(Dispatchers.IO) {
block()
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
996 次 |
| 最近记录: |