如何在Kotlin的Common pool下创建单线程协程上下文?

时间:2018-05-15 16:25:30

标签: java multithreading kotlin threadpool

简短要求:具有创建corotine上下文的能力,该上下文仅在单线程中执行(例如,没有并行性)。

附加要求:最好将现有CommonPool(例如线程池)用于这些任务

实际上,kotlin协程有方法newSingleThreadContext,它将创建单独的线程并将所有任务安排到其中。但是,这是专用线程,所以~1000这样的上下文将需要大量资源。

因此,我希望具有以下特征的上下文:

  • 可以同时执行最多一项任务
  • 此上下文应重用任何其他内容(例如父上下文)。 E.g上下文不应该有其他线程

2 个答案:

答案 0 :(得分:0)

我发现,创建这种上下文没有简单的解决方案。

githuib上存在未解决的问题-https://github.com/Kotlin/kotlinx.coroutines/issues/261

我想我将更新此问题,然后我将找到正确的解决方案。

答案 1 :(得分:0)

这是一个解决方案:

例如,您说withSerialContext(Dispatchers.Default) {doWork()}时,它将在默认的调度程序线程上执行doWork(),但是它的所有部分都将像在runBlocking {}中那样一次执行一次。请注意,即使一次只使用一个线程,也无法保证整个操作都使用同一线程。

suspend fun <T> withSerialContext(
        context: CoroutineDispatcher,
        block: suspend CoroutineScope.() -> T
): T = withContext(SerialContextDispatcher(context), block)

private class SerialContextDispatcher(private val target: CoroutineDispatcher) : CoroutineDispatcher() {

    private val q = ConcurrentLinkedQueue<Runnable>()
    //Whoever CASes this false->true schedules execution of runproc
    private val pending = AtomicBoolean(false)
    //Only one of these runs at a time
    private val runproc = object: Runnable {
        override fun run() {
            while(true) {
                val proc = q.poll();
                if (proc != null) {
                    try {
                        proc.run()
                    }
                    catch (e: Throwable) {
                        target.dispatch(EmptyCoroutineContext, this)
                        throw e
                    }
                } else {
                    pending.set(false);
                    if (q.isEmpty() || !pending.compareAndSet(false, true)) {
                        return
                    }
                }
            }
        }
    }

    override fun dispatch(context: CoroutineContext, block: Runnable) {
        q.add(block)
        if (pending.compareAndSet(false, true)) {
            target.dispatch(EmptyCoroutineContext, runproc)
        }
    }
}