简短要求:具有创建corotine上下文的能力,该上下文仅在单线程中执行(例如,没有并行性)。
附加要求:最好将现有CommonPool(例如线程池)用于这些任务
实际上,kotlin协程有方法newSingleThreadContext
,它将创建单独的线程并将所有任务安排到其中。但是,这是专用线程,所以~1000这样的上下文将需要大量资源。
因此,我希望具有以下特征的上下文:
答案 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)
}
}
}