boost :: coroutine2与CoroutineTS

时间:2019-03-09 14:09:45

标签: c++ boost coroutine boost-coroutine2

Boost :: Coroutine2和CoroutineTS(C ++ 20)是C ++中流行的协程实现。两者都暂停和恢复,但是两种实现遵循完全不同的方法。

CoroutineTS(C ++ 20)

  • 无堆栈
  • 挂起退货
  • 使用特殊关键字
generator<int> Generate()
{
   co_yield;
});

boost :: coroutine2

  • 堆叠
  • 通过电话暂停
  • 请勿使用特殊关键字
pull_type source([](push_type& sink)
{
   sink();
});

是否有任何我只应选择其中一种的特定用例?

1 个答案:

答案 0 :(得分:3)

主要的技术区别是您是否希望能够从嵌套调用中屈服。使用无堆栈协程无法做到这一点。

要考虑的另一件事是,堆栈式协程具有自己的堆栈和上下文(例如信号掩码,堆栈指针,CPU寄存器等),因此它们比无堆栈的协程具有更大的内存占用。这可能是个问题,特别是如果您有一个资源受限的系统或大量同时存在的协程。

我不知道它们如何在现实世界中比较性能,但是总的来说,无栈协程效率更高,因为它们的开销较小(无栈任务切换不必交换栈,存储/加载寄存器和恢复信号掩码等。

有关最小无堆栈协程实现的示例,请参见使用Simon Tatham's coroutinesDuff's Device。很直观,它们尽可能地高效。

此外,this question给出了很好的答案,它们详细介绍了堆栈式协程和非堆栈式协程之间的区别。

如何从无堆栈协程中的嵌套调用中获得收益? 即使我说不可能,也不是100%正确:您可以使用(至少两个)技巧来实现这一点,每个技巧都有一些缺点: 首先,您必须将应该能够产生调用协程的每个调用也转换为协程。现在,有两种方法:

  1. 蹦床方法:您只需循环调用父协程中的子协程,直到返回为止。每次您通知子协程时,如果未完成,您也会产生调用协程。请注意,此方法禁止直接调用子协程,您始终必须调用最外部的协程,然后必须重新输入整个调用堆栈。嵌套深度 n 的调用和返回复杂度为 O(n)。如果您正在等待事件,则该事件只需通知最外部的协程。

  2. 父链接方法:将父协程地址传递给子协程,生成父协程,子协程完成后手动恢复父协程。请注意,此方法禁止直接调用除最内部协程之外的任何协程。这种方法的调用和返回复杂度为 O(1),因此通常更可取。缺点是您必须在某个位置手动注册最内部的协程,以便下一个要恢复外部协程的事件知道直接定位哪个内部协程。

注意:通过调用和返回复杂度,我的意思是通知协程以恢复协程时所采取的步骤数,以及通知协程返回至协程后所采取的步骤数。再次调用通知程序。