【问题标题】:How to cancel the blocking code in the coroutines如何取消协程中的阻塞代码
【发布时间】:2020-02-12 13:45:54
【问题描述】:

我的代码结构如下:

 @Throws(InterruptedException::class)
 fun method() {
     // do some blocking operations like Thread.sleep(...)
 }
 var job = launch {
     method()
 }
 job.cancelAndJoin()

method 由外部库提供,我无法控制它的行为。执行可能需要很长时间,因此在某些情况下应该通过超时取消。

我可以使用 kotlin 协程库提供的withTimeout 函数,但是由于协程的设计,它不能取消带有阻塞的代码。有一些解决方法吗?

【问题讨论】:

    标签: android asynchronous kotlin kotlin-coroutines


    【解决方案1】:

    主要思想是将协程上下文线程池与旧式的可以中断的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)
                }
            }
        }
    }
    

    它提供了与通常的withTimeout 类似的行为,但它还支持运行带有阻塞的代码。

    注意:只有在您知道内部代码使用阻塞并且可以正确处理抛出的InterruptedException 时才应该调用它。大多数情况下,首选withTimeout 函数。

    更新: 自协程 1.3.7 版以来,出现了一个新函数 runInterruptible,它提供了相同的行为。所以这段代码可以简化:

    suspend fun <T> withTimeoutOrInterrupt(timeMillis: Long, block: () -> T) {
        withTimeout(timeMillis) {
            runInterruptible(Dispatchers.IO) {
                block()
            }
        }
    }
    

    【讨论】:

    • 没有更短的版本吗?甚至 AsyncTask 更短...
    • @androiddeveloper,我添加了一个带有新函数runInterruptible的示例。
    • 我明白了。说,关于runInterruptible,如果我想为它存储一些字段怎么办?使用 AsyncTask,我们可以扩展它。现在我们需要包装我们从中得到的东西?
    • 还有如何在 UI 线程上处理取消?
    猜你喜欢
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2019-11-16
    • 2013-04-19
    • 1970-01-01
    相关资源
    最近更新 更多