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
块内。
为什么不能像在 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
块内。