【问题标题】:Best way to call suspend coroutine from Executor(ThreadPoolExecutor)从 Executor(ThreadPoolExecutor) 调用挂起协程的最佳方法
【发布时间】:2022-01-11 09:51:46
【问题描述】:

我目前正在使用相机库和 mlkit 开发人脸检测。

相机库提供了一个FrameProcessor,我在其中以流的方式获取Frame。我在挂起函数中写了FrameProcessingTask

在cameralib内部FrameProcessorThreadPoolExecutor内部被调用

mFrameProcessingExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    for (FrameProcessor processor : mFrameProcessors) {
                        try {
                            processor.process(frame);
                        } catch (Exception e) {
                            LOG.w("Frame processor crashed:", e);
                        }
                    }
                    frame.release();
                }
            });

在我这边我写过:

private val processor = FrameProcessor { frame ->
runBlocking { // used runBlocking to bridge suspend coroutine
    frameProcessingTask(frame)
    }
}

suspend fun frameProcessingTask(frame: Frame) = withContext(Dispatchers.Default)
 //face detection & processing code written here.
}

我的问题:

  1. Executor 中使用runBlocking 是否正确,因为它在每一帧中都被连续调用。
  2. 如果Executor 取消任务,会发生什么暂停runBlocking 部分
  3. 如果processor.process(frame);frameProcessingTask 完成任务之前再次调用会发生什么。

【问题讨论】:

  • 这里为什么需要使用协程? processor.process(frame) 已在其自己的 Executor 中调用。
  • ml 套件检测使用了回调,我需要将其转换为挂起函数并使用它。 @Sergey

标签: android android-camera kotlin-coroutines


【解决方案1】:
  1. 在 Executor 中使用 runBlocking 是否正确,因为它在每一帧中被连续调用。

如果您的代码作为阻塞接口的一部分被调用,该接口期望在方法返回时完成工作,那么您别无选择,只能阻塞线程直到工作完成。 runBlocking 的重点是允许从这种地方调用挂起函数。 FrameProcessor 符合条件。

  1. 如果 Executor 取消任务会导致 runBlocking 部分挂起

如果任务尚未开始,取消只是将任务从队列中移除。

如果任务已经完成,取消无效。

如果任务正在运行,则线程可能会中断以尝试取消任务(这取决于取消任务时使用的mayInterruptIfRunning 参数)。

在最后一种情况下,假设线程已经在执行runBlocking,你可以参考runBlockingdocumentation

如果这个被阻塞的线程被中断(参见 Thread.interrupt),那么协程作业被取消并且这个 runBlocking 调用抛出 InterruptedException。

所以答案是你的协程将被取消(这可能是你所期望的)。

  1. 如果processor.process(frame); 会发生什么?在 frameProcessingTask 完成它的任务之前再次调用

这取决于mFrameProcessingExecutor。如果它是多线程的,那么另一个任务可以与前一个任务并行运行。

【讨论】:

  • 可能还值得一提 runInterruptible - kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/… 如果它支持它也会尝试中断阻塞代码
  • @gildor runInterruptible 用于相反的用例:从协程运行阻塞(但可中断)代码,所以我认为在这个答案中提及它是不相关的
  • 啊,你说得对,我习惯于挂起函数
猜你喜欢
  • 2013-12-08
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 2021-11-03
  • 2011-12-01
  • 2021-03-26
  • 2019-05-30
相关资源
最近更新 更多