Kotlin 协程的 block.startCoroutine() 是如何工作的?

How does Kotlin Coroutine's block.startCoroutine() works?

提问人:Alraj 提问时间:11/2/2023 最后编辑:Alraj 更新时间:11/3/2023 访问量:51

问:

我正在阅读 KEEP 中的协程提案。我在协程生成器部分遇到了这段代码。

fun launch(context: CoroutineContext = EmptyCoroutineContext, block: suspend () -> Unit) =
    block.startCoroutine(Continuation(context) { result ->
        result.onFailure { exception ->
            val currentThread = Thread.currentThread()
            currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
        }
    })

startCoroutine 是 Function Type 的扩展函数(suspend () -> T)

**
 * Starts a coroutine without a receiver and with result type [T].
 * This function creates and starts a new, fresh instance of suspendable computation every time it is invoked.
 * The [completion] continuation is invoked when the coroutine completes with a result or an exception.
 */
@SinceKotlin("1.3")
@Suppress("UNCHECKED_CAST")
public fun <T> (suspend () -> T).startCoroutine(
    completion: Continuation<T>
) {
    createCoroutineUnintercepted(completion).intercepted().resume(Unit)
}

我想知道该函数如何执行它正在扩展的函数。因为我在此代码中没有看到任何内容。startCoroutine()blockthis()

createCoroutineUnintercepted() 也扩展了相同的函数类型,但那里没有源代码实现。

@SinceKotlin("1.3")
public expect fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit>

询问 ChatGPT 没有带来任何答案。它说

当您调用 时,您实际上是在启动块的执行。block.startCoroutine(...)

尝试实现一个简单的函数类型扩展示例,但似乎不起作用。

谁能告诉我这个扩展函数类型是如何工作的?

编译器在暂停函数方面也对此做了什么魔法吗?

kotlin kotlin-coroutines 扩展方法

评论

0赞 Tenfour04 11/2/2023
远离计算机,所以我无法检查,但也许是同一功能类型的扩展功能?createCoroutineUnintercepted
0赞 Alraj 11/2/2023
是的,但没有实现。编辑问题以添加有关的详细信息createCoroutineUnintercepted
1赞 Tenfour04 11/2/2023
这是一个函数。该关键字通常用于多平台代码,在多平台代码中,每个平台的实现方式不同。但在这种情况下,我认为他们正在使用它,因为实现是“编译器魔术”。expect
0赞 Alraj 11/3/2023
我在那里没有看到关键字expect

答:

2赞 Joffrey 11/2/2023 #1

我想知道 startCoroutine() 函数如何执行它正在扩展的函数 block。因为我在此代码中没有看到任何this()。

请记住,它隐式地存在于整个函数主体的上下文中,因此对 类型的函数或属性(包括扩展)的任何调用都可以在不指定 .所以在实践中,实现就像是写成的:thisthisthis.startCoroutine()this.

public fun <T> (suspend () -> T).startCoroutine(
    completion: Continuation<T>
) {
    this.createCoroutineUnintercepted(completion).intercepted().resume(Unit)
}

因此,正如你所看到的,接收器被简单地传递给(因为正如你所指出的,它确实具有相同的接收器类型)。现在,当然,这只是将问题推到另一个函数上。(suspend () -> T)createCoroutineUnintercepted

但是那里没有源代码实现。

事实上,两者都是 Kotlin 编译器识别和转换的特殊函数(称为内部函数)。这就是它们位于 kotlin.coroutines.intrinsics中的原因。它们是语言提供的基本构建块,以便构建更用户友好的框架(例如 Kotlinx 协程库)。createCoroutineUninterceptedsuspendCoroutineUninterceptedOrReturn

我推荐这篇博文来了解什么是基本语言原语,以及我们如何从中构建像 Kotlinx 协程这样的框架: https://blog.kotlin-academy.com/kotlin-coroutines-animated-part-1-coroutine-hello-world-51797d8b9cd4

除了协程的 KEEP 之外,您可能还会发现以下详细的技术文档也很有用: https://github.com/JetBrains/kotlin/blob/master/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutines-codegen.md

尝试实现一个简单的函数类型扩展示例,但似乎不起作用。

关于这个,你只是打印了(使用模板语法),但你没有调用它。您可以在代码中添加括号以使其正常工作(为此,您需要在字符串模板中添加大括号)。因此,只需替换为,它实际上会调用它并打印您期望的内容:this$this$this${this()}

inline fun (() -> Int).start() {
    println("start received ${this()}")
}

fun launch(block: () -> Int) {
    block.start()
}

fun main() {
    launch {
        1
    }
}

评论

0赞 Alraj 11/3/2023
关于打印,是看函数类型是执行还是只是作为函数对象接收,因为根据老大哥 ChatGPT 的说法,它是执行:P$this
0赞 Joffrey 11/3/2023
ChatGPT 经常出错,不可信。然而,对于它的辩护,它专门回答了 ,从技术上讲,它确实在某个时候执行了接收器block.startCoroutine()