实现协程的不同方式

Different ways of implementing a coroutine

我目前能想到两种实现协程的方式:

  1. 每当协程启动时,不是将局部变量存储在堆栈上,而是从堆中获取一块内存并用它来存储局部变量。这样,局部变量不会被破坏,任何被调用的函数都可以 return 稍后及时到这个函数。但是在这种情况下,任何不是协程的被调用函数都必须在主调用堆栈上 运行 。我不知道这是否会导致任何问题。有人可以确认一下吗!
  2. 每当协程启动时,分配比该协程所需的更多的内存。这就像该协程的某种自定义调用堆栈。在这种情况下,this 调用的所有子函数将与该协程存储在一起。但是这个实现可能需要太多的冗余内存。

我认为这两个通常被称为无堆栈协程和堆栈协程。

理论上还有哪些其他可行的协程实现方式?它们的优点和缺点是什么?哪些语言使用哪些实现?

您的选项 (1) 确实是一个无堆栈协程,这就是它在 Kotlin 中的实现方式,例如,通常是 Javascript (async/await)。当您不一定拥有其他方法所需的调用堆栈的 low-level 控制权时,这就是您的做法。使用此策略的语言需要以某种方式标记可挂起的函数。这就是所谓的“red/blue 函数问题”。参见:https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/

low-level 控制调用堆栈的语言可以通过多种方式实现协程,但 none 看起来像你的选择(2 ).它们通常涉及在需要时将数据复制到调用堆栈中或从调用堆栈中复制出来(如 Java 项目 Loom)或使用完全不同的数据结构代替调用堆栈(如早期的 Go 实现)。在这些语言中,coroutine-callable 函数通常不需要特殊标记。