Vad*_*P22 21 c++ asynchronous language-design c++20 c++-coroutine
在 Rust 中,异步函数不需要在堆上分配。函数async返回编译器生成的结构,您可以在该结构上调用编译器生成的poll方法。异步的设计看起来逻辑清晰。
C++中协程的设计很奇怪。它迫使您在堆上进行分配,因为您没有其他方法可以使用co_return.
(可以创建一个自定义分配器来在堆栈上的缓冲区中进行分配,但这会使代码不必要地复杂化。)
为什么在 C++ 的设计中决定协程返回的对象必须有一个promise_type?
为什么await_ready,,,await_suspend还await_resume不够?
(这看起来很奇怪,这就是强制你进行分配的原因;你不能直接构造一个SomeTask<T>对象(使用三个await_*方法)并返回它。)
我们如何在没有自定义分配器的情况下制作零分配协程?
Nic*_*las 20
本质上,它迫使您在堆上进行分配,因为您没有其他方法可以使用
co_return
这不是分配的原因。
协程需要存储来完成其工作。不仅是返回值的编组,而且还用于跟踪整个事情。协程的堆栈,即必须暂停和恢复的东西,是其中的一部分。
协程的全部意义在于它可以暂停执行并让某人恢复执行。这个人是谁并不能静态地获知。这就是为什么需要动态分配的原因;协程的生命周期不受其初始调用者范围的限制。
如果函数 X 调用协程 A,并且协程 A 挂起自身以等待某个异步请求,则函数 X 可能会将协程返回给等待它的其他人。这意味着函数 X 的调用堆栈消失了。如果协程 A 存在于函数 X 的堆栈上,那么它的存储空间现在就消失了。
那很糟。
C++ 将协程 A 存储在动态分配的内存中,以使其能够在调用中存活下来。这是协程的假定默认情况。
据推测,您所描述的情况是函数 X 本身是等待 A 的协程,或者在 A 完成之前不会离开自己的作用域。这将允许 A 的协程状态毫无问题地存在于 X 的堆栈上。如果检测到这些条件,C++ 编译器可以对其进行优化;他们可以省略动态分配。
但除此之外,动态分配是必要的。
我不知道鲁斯特。所以我不知道 Rust 的async功能是做什么的。也许它的异步函数无法持续超出其调用范围的边界。也许 Rust 能够更好地检测异步函数何时需要能够超出其调用者的范围。也许您必须明确告诉 Rust 当您希望协程逃脱其调用者的作用域时。我不知道。
但 C++ 不是这样的。C++ 协程被假定离开其调用函数的范围。