[英]How can I create single-thread coroutine context under Common pool in Kotlin?
簡短要求:能夠創建 corotine 上下文,該上下文僅在單線程中執行(例如,沒有並行性)。
附加要求:這些任務最好使用現有的 CommonPool(例如線程池)
實際上,kotlin 協程有newSingleThreadContext
方法,它將創建單獨的線程並將所有任務調度到其中。 但是,這是專用線程,因此大約 1000 個這樣的上下文將需要大量資源。
因此,我想要具有以下特征的上下文:
這是一個解決方案:
例如,當您說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)
}
}
}
我發現,沒有簡單的解決方案來創建這樣的上下文。
githuib 上有未解決的問題 - https://github.com/Kotlin/kotlinx.coroutines/issues/261
我想我會更新這個問題然后我會找到正確的解決方案。
從kotlinx.coroutines
庫的1.6.0
版本開始,我們可以在CoroutineDispatcher
對象上使用limitedParallelism
函數,它可以讓您限制並行度而無需創建額外的線程池,並提供了一種統一的方式來為未綁定並行度創建調度程序。
用法示例:
class UserRepository {
private val dbDispatcher = Dispatchers.IO.limitedParallelism(1)
suspend fun getUserById(userId: Int): User? = withContext(dbDispatcher) {
executeQuery("SELECT * FROM users WHERE id = $1", userId).singleOrNull()
}
}
應該可以解決以下問題:
最多可以同時執行一項任務,並且上下文不應包含額外的線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.