Kotlin 协程 - 如何在后台运行并在调用方线程中使用 result?



主要思想是具有非挂起函数runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit),该函数在后台异步运行一些工作(另一个线程(,并在工作完成后 - 在调用者线程中运行回调(runInBackgroundAndUseInCallerThread启动的线程(。

下面我写了一个示例代码,但我不确定它是否正确以及它是否可能。用println("1/2/3/...")我标记了所需的呼叫顺序。getDispatcherFromCurrentThread- 如果可以实现此功能,则可以使用解决方案,但我不知道如何实现它,

这样做是否正确。因此,请不要将其视为唯一的解决方案。

import kotlinx.coroutines.*
import kotlin.concurrent.thread
fun main() {
println("1")
runInBackgroundAndUseInCallerThread {
println("4")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from main"
}
println("2")
thread(name = "Second thread") {
runInBackgroundAndUseInCallerThread {
println("5")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from Second thread"
}
}
println("3")
Thread.sleep(3000)
println("6")
}
fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
val dispatcherFromCallerThread: CoroutineDispatcher = getDispatcherFromCurrentThread()
CoroutineScope(Dispatchers.IO).launch {
val result: SomeModel = getModelResult()
launch(dispatcherFromCallerThread) { callback(result) }
}
}
data class SomeModel(val someField: String)
suspend fun getModelResult(): SomeModel {
delay(1000)
return SomeModel("TestField")
}
fun getDispatcherFromCurrentThread(): CoroutineDispatcher {
// TODO: Create dispatcher from current thread... How to do that?
}

除非线程被设计为作为调度程序工作,否则没有一种通用的方法可以做到这一点。 想到的唯一方法是runBlocking是可重入的,并将在现有线程中创建事件循环,但是它将阻止所有非协程代码在该线程上执行,直到它完成。

这最终看起来像:

fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
callback(runBlocking(Dispatchers.IO) {
getModelResult()
})
}

dispatcher确实是一个coroutineContext,在scope中使用时是有意义的 因此,如果要将父范围的调度程序传递到子范围,则可以这样做。

GlobalScope.launch {
val dispatcher = this.coroutineContext
CoroutineScope(dispatcher).launch {
}
}

因此getDispatcherFromCurrentThread应该是这样的。

fun getDispatcherFromCurrentThread(scope: CoroutineScope): CoroutineContext {
return scope.coroutineContext
}

GlobalScope.launch {
val dispatcher = getDispatcherFromCurrentThread(this)
CoroutineScope(dispatcher).launch {
}
}

后台异步运行一些工作(另一个线程(并在工作完成后 - 在调用者线程中运行回调

首先尝试回答这个问题:当后台工作正在进行时,调用线程应该做什么

显然,它不能继续到代码的下一行,该代码应该在完成后台工作后运行。

您也不希望它阻止和等待。

那么它应该运行什么代码呢?

唯一合理的答案如下:调用线程应该在其最顶层的执行(入口点函数(运行无限事件循环。问题中的代码应位于提交到事件循环的事件处理程序中。在要等待后台工作时,处理程序必须返回,以便线程可以继续处理其他事件,并且您必须准备好在后台工作完成后提交另一个处理程序。对应于您的callback的第二个处理程序称为延续,Kotlin 会自动提供它。实际上,您不需要自己的回调。

但是,现在出现了最敏感的问题:如何将延续提交到事件循环?这不是您可以抽象的东西,您必须使用一些特定于相关事件循环的API。

这就是为什么科特林有Dispatcher的概念。它捕获将延续调度到所需线程的特定于案例的关注。您似乎想要解决它,而无需编写专用于每个特定事件循环的调度程序,不幸的是这是不可能的。

最新更新