gpt4 book ai didi

c++ - 无堆栈 C++20 协程有问题吗?

转载 作者:IT老高 更新时间:2023-10-28 13:58:24 31 4
gpt4 key购买 nike

基于以下内容,看起来 C++20 中的协程将是无堆栈的。

https://en.cppreference.com/w/cpp/language/coroutines

我担心的原因有很多:

  • 在嵌入式系统上,堆分配通常是 Not Acceptable 。
  • 在低级代码中,嵌套 co_await 会很有用(我不相信无堆栈协程允许这样做)。

  • With a stackless coroutine, only the top-level routine may be suspended. Any routine called by that top-level routine may not itself suspend. This prohibits providing suspend/resume operations in routines within a general-purpose library.



    https://www.boost.org/doc/libs/1_57_0/libs/coroutine/doc/html/coroutine/intro.html#coroutine.intro.stackfulness
  • 由于需要自定义分配器和内存池,因此代码更加冗长。
  • 如果任务等待操作系统为其分配一些内存(没有内存池),则速度较慢。

  • 鉴于这些原因,我真的希望我对当前的协程是什么是非常错误的。

    问题分为三部分:
  • 为什么 C++ 会选择使用无堆栈协程?
  • 关于在无堆栈协程中保存状态的分配。我可以使用 alloca() 来避免通常用于协程创建的任何堆分配吗?

  • coroutine state is allocated on the heap via non-array operator new. https://en.cppreference.com/w/cpp/language/coroutines


  • 我对 c++ 协程的假设是错误的,为什么?

  • 编辑:

    我现在正在讨论协程的 cppcon 谈话,如果我找到我自己问题的任何答案,我会发布它(目前没有)。

    CppCon 2014:Gor Nishanov “await 2.0:Stackless Resumable Functions”

    https://www.youtube.com/watch?v=KUhSjfSbINE

    CppCon 2016:James McNellis“C++ 协程简介”

    https://www.youtube.com/watch?v=ZTqHjjm86Bw

    最佳答案

    转发:当这篇文章只说“协程”时,我指的是协程的概念,而不是特定的 C++20 特性。在谈论这个功能时,我将其称为“co_await”或“co_await 协程”。

    关于动态分配

    Cppreference 有时使用比标准更宽松的术语。 co_await作为一项“需要”动态分配的功能;此分配是来自堆还是来自静态内存块或分配提供者的任何问题。这种分配可以在任意情况下省略,但由于标准没有说明它们,您仍然必须假设任何 co_await 协程都可以动态分配内存。

    co_await 协程确实有机制让用户为协程的状态提供分配。因此,您可以将堆/空闲存储分配替换为您喜欢的任何特定内存池。
    co_await作为一项功能经过精心设计,可以从任何 co_await 的使用点中删除冗长的内容。 - 对象和功能。 co_await机械非常复杂和错综复杂,在几种类型的对象之间有很多相互作用。但是在暂停/恢复点,它总是看起来像 co_await <some expression> .为可等待对象和 promise 添加分配器支持需要一些冗长的内容,但这种冗长的内容存在于使用这些东西的地方之外。

    使用 alloca对于协程将...非常不适合 co_await 的大多数用途.虽然围绕此功能的讨论试图隐藏它,但事实是 co_await作为一项功能是为异步使用而设计的。这就是它的预期目的:停止函数的执行并安排该函数在潜在的另一个线程上恢复,然后将任何最终生成的值引导到一些可能与调用协程的代码有些距离的接收代码。
    alloca不适用于该特定用例,因为允许/鼓励协程的调用者执行任何操作,以便其他线程可以生成该值。 alloca分配的空间因此将不再存在,这对存在于其中的协程有点不利。

    还要注意,这种情况下的分配性能通常会因其他考虑而相形见绌:线程调度、互斥锁和其他东西通常需要正确调度协程的恢复,更不用说从任何异步获取值所需的时间过程正在提供它。因此,在这种情况下,需要动态分配的事实并不是真正的重要考虑因素。

    现在,有些情况下就地分配是合适的。生成器用例适用于您想要暂停函数并返回一个值,然后从函数停止的地方继续并可能返回一个新值的情况。在这些场景中,调用协程的函数的堆栈肯定仍然存在。
    co_await支持这样的场景(虽然 co_yield ),但它以一种不太理想的方式这样做,至少在标准方面是这样。由于该功能是为上下挂起而设计的,因此将其转换为挂起协程会产生这种不需要动态的动态分配的效果。

    这就是标准不需要动态分配的原因;如果编译器足够聪明,可以检测到生成器的使用模式,那么它可以删除动态分配,只在本地堆栈上分配空间。但同样,这是编译器可以做的,而不是必须做的。

    在这种情况下,alloca -基于分配将是适当的。

    它是如何进入标准的

    简而言之,它进入标准是因为它背后的人投入了工作,而替代方案背后的人没有。

    任何协程的想法都是复杂的,并且总会有关于它们的可实现性的问题。例如,“resumeable functions”提案看起来很棒,我很想在标准中看到它。但实际上没有人在编译器中实现它。所以没有人可以证明这实际上是你可以做的事情。哦当然,这听起来可以实现,但这并不意味着它可以实现。

    记住 what happened the last time “声音可实现”被用作采用功能的基础。

    如果你不知道它可以被实现,你就不想标准化。如果你不知道它是否真的解决了预期的问题,你就不想标准化。

    Gor Nishanov 和他在 Microsoft 的团队致力于实现 co_await .他们这样做了多年,改进了他们的实现等。其他人在实际生产代码中使用了他们的实现,并且似乎对其功能非常满意。 Clang 甚至实现了它。尽管我个人不喜欢它,但不可否认的是co_await是一个成熟的功能。

    相比之下,一年前作为与 co_await 竞争的想法提出的“核心协程”替代方案。未能获得牵引力 in part because they were difficult to implement .这就是为什么co_await被采用:因为它是人们想要的一种经过验证、成熟且可靠的工具,并且具有改进代码的能力。
    co_await不适合所有人。就我个人而言,我可能不会经常使用它,因为对于我的用例来说,纤维工作得更好。但它非常适合它的特定用例:上下悬挂。

    关于c++ - 无堆栈 C++20 协程有问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57163510/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com