这个问题与我对 existing coroutine implementations in Java 的问题有关。如果正如我所怀疑的那样,事实证明 Java 目前没有完整的协程实现,那么实现它们需要什么?
正如我在那个问题中所说,我知道以下内容:
- 您可以在后台将“协程”实现为线程/线程池。
- 您可以在幕后使用 JVM 字节码做一些棘手的事情,以使协程成为可能。
- 所谓的“达芬奇机器”JVM 实现具有使协同程序无需字节码操作即可执行的原语。
- 还有各种基于 JNI 的协程方法也是可能的。
我将依次解决每个人的不足之处。
基于线程的协程
这种“解决方案”是病态的。协程的全部意义在于 避免 线程、锁定、内核调度等开销。协程应该轻便、快速,并且只在用户空间中执行。根据具有严格限制的全倾斜线程来实现它们会消除所有优势。
JVM 字节码操作
这个解决方案更实用,尽管有点难以实现。这与跳转到 C 中的协程库的汇编语言(这是其中的多少工作)大致相同,优点是您只需担心并正确处理一种架构。
它还会限制您只能在完全兼容的 JVM 堆栈(这意味着,例如,没有 Android)上运行您的代码,除非您可以找到一种方法在不兼容的堆栈上执行相同的操作。但是,如果您确实找到了一种方法来执行此操作,那么您现在已经使系统复杂性和测试需求增加了一倍。
达芬奇机器
Da Vinci Machine 很适合做实验,但由于它不是标准的 JVM,因此它的功能并非随处可用。事实上,我怀疑大多数生产环境会明确禁止使用达芬奇机器。因此我可以用它来做很酷的实验,但不能用于我希望发布到现实世界的任何代码。
这也有类似于上面的 JVM 字节码操作解决方案的附加问题:不适用于替代堆栈(如 Android 的)。
JNI 实现
该解决方案使在 Java 中执行此操作的意义完全没有意义。 CPU 和操作系统的每一种组合都需要独立测试,每一种都是潜在的令人沮丧的细微故障点。或者,当然,我可以将自己完全限制在一个平台上,但这也使得使用 Java 做事的意义完全没有意义。
所以…
有没有什么方法可以在不使用这四种技术中的一种的情况下在 Java 中实现协程?还是我会被迫改用那四种味道最淡的一种(JVM 操作)?
编辑添加:
只是为了确保包含混乱,这是与 我的另一个 问题 相关 的问题,但不一样。那个人正在寻找 现有的 实施方式,以避免不必要地重新发明轮子。这是一个问题,如果另一个被证明无法回答,一个人将如何在 Java 中实现协程。目的是在不同的线程上保留不同的问题。
原文由 JUST MY correct OPINION 发布,翻译遵循 CC BY-SA 4.0 许可协议
我会看看这个:http: //www.chiark.greenend.org.uk/~sgtatham/coroutines.html ,它非常有趣,应该提供一个很好的起点。但是我们当然使用 Java,所以我们可以做得更好(或者可能更糟,因为没有宏 :))
根据我对协同程序的理解,您通常有一个 生产者 和一个 消费者 协同程序(或者至少这是最常见的模式)。但从语义上讲,您不希望生产者调用消费者,反之亦然,因为这会引入不对称性。但是考虑到基于堆栈的语言的工作方式,我们需要有人来做调用。
所以这是一个非常简单的类型层次结构:
当然,现在最困难的部分是 实现 接口,特别是很难将计算分解为单独的步骤。为此,您可能需要一整套其他 持久控制结构。基本思想是我们想要模拟非本地控制转移(最后有点像我们正在模拟
goto
)。我们基本上希望不再使用堆栈和pc
(程序计数器),方法是将当前操作的状态保留在堆中而不是堆栈中。因此我们需要一堆辅助类。例如:
假设在一个理想的世界中,您想编写一个看起来像这样的消费者(伪代码):
我们需要抽象局部变量,如
is_done
和other_state
我们需要抽象 while 循环本身,因为我们的yield
就像操作不会使用堆。因此,让我们创建一个 while 循环抽象和相关类:这里的基本技巧是将 局部 变量移动为 类 变量并将范围块转换为类,这使我们能够在产生返回值后“重新进入”我们的“循环”。
现在来实现我们的生产者
可以对其他基本控制流结构使用类似的技巧。理想情况下,您可以构建这些辅助类的库,然后使用它们来实现这些简单的接口,最终为您提供协同例程的语义。我相信我在这里写的一切都可以概括和扩展。