gpt4 book ai didi

java - 在没有 JVM 支持的情况下,如何在 JVM 语言中实现协程?

转载 作者:行者123 更新时间:2023-12-02 11:29:35 24 4
gpt4 key购买 nike

这个问题是在阅读 Loom proposal 后提出的,它描述了一种在 Java 编程语言中实现协程的方法。

该提案特别指出,要在语言中实现此功能,将需要额外的 JVM 支持。

据我了解,JVM 上已经有几种语言将协程作为其功能集的一部分,例如 Kotlin 和 Scala。

那么这个功能在没有额外支持的情况下是如何实现的,没有它是否可以有效地实现呢?

最佳答案

tl;博士 概括:

Particularly this proposal says that to implement this feature in the language the additional JVM support will be required.



当他们说“必需”时,它们的意思是“需要以一种既高效又可在语言之间互操作的方式实现”。

So how this feature is implemented without additional support



有很多方法,最容易理解它是如何工作的(但不一定最容易实现)是在 JVM 之上用你自己的语义实现你自己的 VM。 (请注意,这不是实际完成的方式,这只是关于为什么可以完成的直觉。)

and can it be implemented efficiently without it ?



并不真地。

稍长的解释 :

请注意,Project Loom 的一个目标是将这种抽象纯粹作为一个库来引入。这具有三个优点:
  • 引入一个新的库比改变 Java 编程语言要容易得多。
  • 在 JVM 上用每种语言编写的程序都可以立即使用库,而 Java 语言功能只能由 Java 程序使用。
  • 可以实现具有相同 API 且不使用新 JVM 功能的库,这将允许您通过简单的重新编译(尽管性能较低)编写在旧 JVM 上运行的代码。

  • 然而,将它实现为一个库排除了巧妙的编译器技巧将协程转换为其他东西,因为不涉及编译器。如果没有巧妙的编译器技巧,获得良好的性能就会困难得多,这也是对 JVM 支持的“要求”。

    更长的解释 :

    一般而言,所有常用的“强大”控制结构在计算意义上都是等效的,并且可以相互使用。

    在那些“强大的”通用控制流结构中,最著名的是著名的 GOTO ,另一个是Continuations。然后是Threads和Coroutines,一个人们不常想到的,但也相当于 GOTO : 异常(exception)。

    另一种可能性是重新定义的调用堆栈,以便程序员可以将调用堆栈作为对象访问,并且可以修改和重写。 (例如,许多 Smalltalk 方言就是这样做的,它也有点像在 C 和汇编中这样做的方式。)

    只要您拥有其中之一,您就可以拥有所有这些,只需在另一个之上实现一个。

    JVM 有两个:异常和 GOTO ,但 GOTO在 JVM 中不是通用的,它是极其有限的:它只能在单个方法中工作。 (它本质上仅用于循环。)因此,这给我们留下了异常。

    因此,这是您问题的一种可能答案:您可以在异常之上实现协同例程。

    另一种可能性是根本不使用 JVM 的控制流并实现您自己的堆栈。

    但是,这通常不是在 JVM 上实现协同例程时实际采用的路径。最有可能的是,实现协程的人会选择使用 Trampolines 并将执行上下文部分重新定义为对象。也就是说,例如,如何在 CLI 上的 C♯ 中实现 Generators(不是 JVM,但挑战类似)。 C♯ 中的生成器(基本上是受限的半协同例程)是通过将方法的局部变量提升到上下文对象的字段中并在每个 yield 处将该方法拆分为该对象的多个方法来实现的。语句,将它们转换为状态机,并通过上下文对象上的字段小心地将所有状态更改线程化。和之前 async/ await作为一种语言特性出现,一位聪明的程序员也使用相同的机制实现了异步编程。

    然而 ,这就是你所指的文章最有可能提到的:所有这些机器都是昂贵的。如果您实现自己的堆栈或将执行上下文提升到一个单独的对象中,或者将所有方法编译为一个巨大的方法并使用 GOTO无处不在(由于方法的大小限制,这甚至不可能),或者使用异常作为控制流,至少这两件事之一将是正确的:
  • 您的调用约定与其他语言所期望的 JVM 堆栈布局不兼容,即您失去了互操作性。
  • JIT 编译器不知道你的代码到底在做什么,并以字节码模式、执行流模式和使用模式(例如,抛出和捕获大量异常)呈现它不期望也不知道如何优化,即你失去了性能。

  • Rich Hickey(Clojure 的设计者)曾在一次演讲中说:“尾调用、性能、互操作。二选一。”我将此概括为我称之为 Hickey 的格言:“高级控制流、性能、互操作。选择二。”

    事实上,即使是互操作性或性能之一,通常也很难实现。

    此外,您的编译器将变得更加复杂。

    当构造在 JVM 中本地可用时,所有这些都会消失。想象一下,例如,如果 JVM 没有线程。然后,每个语言实现都会创建自己的线程库,它很难、复杂、缓慢,并且不与任何其他语言实现的线程库互操作。

    最近一个真实的例子是 lambdas:JVM 上的许多语言实现都有 lambdas,例如斯卡拉。然后 Java 也添加了 lambda,但是因为 JVM 不支持 lambda,它们必须以某种方式进行编码,而且 Oracle 选择的编码与 Scala 之前选择的不同,这意味着您无法传递 Java lambda到需要 Scala 的 Scala 方法 Function .在这种情况下,解决方案是 Scala 开发人员完全重写了他们的 lambda 编码,以与 Oracle 选择的编码兼容。这实际上在某些地方破坏了向后兼容性。

    关于java - 在没有 JVM 支持的情况下,如何在 JVM 语言中实现协程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48033944/

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