Kotlin 协程:在 Sequence::map 中调用 Deferred::await

Kotlin Coroutines: Calling Deferred::await in Sequence::map

为什么不能像在 List::map 中那样在 Sequence::map 函数中调用 Deferred::await?

我做了一个小例子

fun example() = runBlocking {

    val list = listOf(1, 2, 3, 4)

    list.map { async { doSomething(it) } }
            .map { it.await() }

    list.asSequence()
            .map { async { doSomething(it) } }
            .map { it.await() }         // Error: Kotlin: Suspension functions can be called only within coroutine body

}

如您所见,最后一条语句无法编译。

这是因为 list.map 是一个 inline fun,这可能是因为 returns 一个新列表是一个急切的操作。 inline fun 可以容忍 suspend 块,因为它更像是一个宏:它被扩展到调用站点。只要调用站点在 suspend 块内,就可以正常工作。

另一方面,

sequence.map 是惰性的,当您从序列中提取项目时,它只是将另一个 lambda 添加到最终将执行的操作管道中。

在可暂停世界中最接近惰性序列的是 Flow,但它有一个不同的模型,您可以一次性将所有数据推送给您,而您可以从惰性序列中提取项目一个一个排序。

添加到 Marko 的正确答案中:

因为序列是惰性的,await() 调用可能发生在 runBlocking 完成之后,基本上。在您开始从列表中拉出元素之前,异步调用和等待都不会发生。

并且在上面的代码中,没有任何东西将元素从序列中拉出,因此序列上的映射操作都不会发生在 runBlocking 块内。