tl; dr 摘要:
特别是,该建议说,要以该语言实现此功能,将需要附加的JVM支持。
当他们说“必需”时,它们的意思是“必须以在语言之间既高效又可互 *** 作的方式实现”。
因此,如何在没有其他支持的情况下实现此功能
有很多方法,最容易理解它如何工作(但不一定最容易实现)的方法是,在JVM之上使用自己的语义来实现自己的VM。(请注意,这 并不是
实际完成的方式,这只是关于 为什么 可以执行的一种直觉。)
没有它,能否有效实施?
并不是的。
稍长的解释 :
注意,Project Loom的一个目标是 纯粹 将这种抽象作为一个库来引入。这具有三个优点:
- 引入新库比更改Java编程语言要容易得多。
- 可以在JVM上以每种单一语言编写的程序立即使用库,而Java语言功能只能由Java程序使用。
- 可以实现具有不使用新的JVM功能的相同API的库,这将允许您编写具有在旧JVM上运行的代码,并且可以进行简单的重新编译(尽管性能较低)。
但是,将其实现为库可避免巧妙的编译器技巧,因为 它们不涉及编译器
,因此可以将协例程转换为其他东西。没有聪明的编译器技巧,要获得良好的性能要困难得多,因此,这是对JVM支持的“要求”。
更长的解释 :
通常,所有通常的“强大”控制结构在计算意义上都是等效的,并且可以彼此实现。
在那些“强大的”通用控制流结构中,最著名的是尊贵的
GOTO,另一种是Continuations。然后是线程和协程,这是人们不常想到的,但这也等同于
GOTO:异常。
另一种可能性是重新定义调用堆栈,以便程序员可以将调用堆栈作为对象进行访问,并且可以对其进行修改和重写。(例如,许多Smalltalk方言都这样做,这也有点像在C和汇编语言中那样。)
只要拥有 其中 之一,就可以通过在另一个之上实现而拥有 所有 这些。
JVM有两个:Exceptions和
GOTO,但是
GOTOJVM中的 并不是 通用的,它非常有限:它仅 在
单个方法中起作用。(它实际上仅用于循环。)因此,这给我们留下了异常。
因此,这是对您的问题的一种可能的答案:您可以在Exceptions之上实现协同例程。
另一种可能性是根本不使用JVM的控制流 , 而是实现自己的堆栈。
但是,这通常不是在JVM上实现协同例程时实际采用的路径。最有可能实现共同例程的人会选择使用蹦床并将部分执行上下文重新定义为对象。就是说,例如,如何在CLI的C♯中实现Generators(不是JVM,但是挑战是相似的)。通过将方法的局部变量提升到上下文对象的字段中,并在每个
yield语句的该对象上将方法拆分为多个方法,然后将它们转换为状态,可以实现C♯中的生成器(基本上是受限的半协例程)。机器,并仔细地通过上下文对象上的字段线程化所有状态更改。和之前
async/
await
作为一种语言功能出现了,一个聪明的程序员也使用相同的机器实现了异步编程。
但是 ,这就是您最可能提到的文章:所有这些机器都是昂贵的。如果您实现自己的堆栈或将执行上下文提升到一个单独的对象中,或者将所有方法编译为一个
巨型 方法并
GOTO在任何地方使用(由于方法的大小限制,这甚至是不可能的),或者使用Exceptions作为控件-流程,至少这两项是正确的:
- 您的调用约定与其他语言期望的JVM堆栈布局不兼容,即失去了 互 *** 作性 。
- JIT编译器不知道什么是地狱你的代码是干什么的,并呈现字节码图案,执行流程模式和使用模式(如抛出和捕获 极大的相 量例外),它不指望,不知道如何优化,即失去 性能 。
Rich Hickey(Clojure的设计师)曾经在一次演讲中说:“尾巴通话,表演,互 *** 作。选择两个。” 我将其概括为我称为 Hickey的Maxim
:“高级控制流,性能,互 *** 作。选择两个。”
事实上,这通常很难实现,甚至 一个 互 *** 作或性能。
而且,您的编译器将变得更加复杂。
当该构造在JVM中本地可用时,所有这些都消失了。想象一下,例如,如果JVM没有线程。然后,每种语言实现都将创建自己的线程库,该库很难,复杂,缓慢且不会与任何
其他 语言实现的线程库互 *** 作。
最近的一个真实示例是lambda:JVM上的许多语言实现都有lambda,例如Scala。然后,Java也添加了lambda,但是由于JVM不支持lambda,因此必须对其进行
编码 ,并且Oracle选择的编码与Scala之前选择的编码不同,这意味着您无法传递Java
lambda。期望Scala的Scala方法
Function。在这种情况下,解决方案是Scala开发人员完全重写了他们的lambda编码,以与Oracle选择的编码兼容。实际上,这在某些地方破坏了向后兼容性。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)