论坛首页 编程语言技术论坛

C# 4 DLR & Java 7 Invokedynamic

浏览 3247 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2009-03-20   最后修改:2009-03-20
http://www.iteye.com/topic/260510
喜欢或者厌恶MS,都要看看 C# 4.0

http://www.iteye.com/news/2385
Java平台的DLR:Da Vinci Machine项目

http://www.iteye.com/news/2307
Java7的invokedynamic指令草案已经公布

************* 以上为最近看到的内容,以下为本人的感想 ************

两大静态语言,C#和Java,都在引入动态语言特性。

C# 4 DLR
Java 7 Invokedynamic

有一种说法,Java 7 的 Invokedynamic 是指令,效率会高。
对此有些怀疑和不解。
Invokedynamic 应该也会在运行时做一定的动态解析动作,和 DLR 在运行时做的工作,应该比较类似。
   发表时间:2009-03-21  
呵呵,正好我也关注着这方面的内容。有兴趣的话楼主可以看看去年我写的些记录,这篇:LINQ与DLR的Expression tree(2):简介DLR

invokedynamic有机会比DLR具备更高的运行效率,主要是因为JVM的许多实现都比.NET的CLR要更“动态”。

以Hotspot JVM的运行模式为例,Java程序被装载进来后一开始主要是以解释模式执行,等到一定时间之后,某些方法变得比较“热”(执行密度高),就有机会被JIT为本地代码。根据JVM启动参数和程序运行状况的不同,Hotspot可能采取不同的JIT和优化策略。JVM可以假定程序大部分时间某些条件满足某些条件(例如持有某个锁的几乎总是同一个线程),并采用激进优化;如果运行到某一时刻,假定的条件不再满足了,Hotspot也可以退回到解释模式继续执行。整个过程中实际被执行的代码的状况是非常动态的。

CLR这边则总是在程序刚开始的就将每个调用到的方法都JIT为本地代码再执行。这样,唯一“动态”的地方就是:JIT之后的代码是放在一个所谓“代码堆”上的(与分代式GC管理的对象/大对象堆相互独立);当这个堆的大小达到某个阈值时,CLR就会将JIT过的代码清空,然后重新开始托管方法调用->JIT->以本地代码执行的流程。
CLR的指令集,MSIL(或者叫CIL)的设计使得它并不太适合于解释执行,因为指令本身是多态的。于此相对,JVM的指令集有许多是单态的,指令本身就包含了类型信息,更有利于解释执行时的效率。未来的CLR转向更动态的执行模型的可能性也因此受到了一些by-design的限制。

DLR为了支持动态语言中可能发生的方法重定义,或者是同一个方法调用点可能要调用不同类型对象的同名方法等状况,不得不提高运行时的动态性。与JVM增加invokedynamic指令不同,DLR的实现并不依赖CLR的任何改变;底下的CLR跟.NET 2.0时的CLR并没有大的变化。那怎么实现代码的动态性呢?DLR采用了更高层的抽象模型作为执行模型:Expression Tree。
DLR中每个方法调用点(CallSite)都保存着一些Expression Tree;基于DLR的动态语言实现也是将源码编译到Expression Tree之后交给DLR。这些Expression Tree可以被编译为MSIL变成动态方法(DynamicMethod),由CLR执行。DLR也会对代码做一些假设,满足假设的时候就重用以前编译好的动态方法,假设不成立的时候就重新构建Expression Tree,然后编译为MSIL得到动态方法,然后由CLR执行。

所以为什么invokedynamic有机会比DLR有更高的运行效率呢?因为JVM在底层实现了更多的动态性,以C++来实现了调用点的link/relink过程,Java一边只要说明link target是哪里,要满足的条件是什么就行;DLR则完全靠C#来实现调用点的link/relink过程,也靠C#或者其它.NET语言来说明link target与对应的条件。除非哪天C#能在速度上完胜C++,不然……嗯,呵呵。

不过实际东西出来之前谁也说不准。我也只能说invokedynamic有机会比DLR快,并不保证一定如此。至少,非Sun Hotspot JVM对invokedynamic的支持能有多好也得放入考虑之中。目前的DLR还有很大的改良余地,而invokedynamic也还只有prototype,还没达到最佳状态。让时间来告诉我们结果就是了~

P.S. 话说回来,使用更高级的语言来编程,长远来说倒也是更有潜力的;think Squeak,think Rubinius,think PyPy……
已被评为好帖!
   发表时间:2009-03-23  

RednaxelaFX 对这方面研究很深哪。

RednaxelaFX 写道

CLR的指令集,MSIL(或者叫CIL)的设计使得它并不太适合于解释执行,因为指令本身是多态的。于此相对,JVM的指令集有许多是单态的,指令本身就包含了类型信息,更有利于解释执行时的效率。未来的CLR转向更动态的执行模型的可能性也因此受到了一些by-design的限制。


指令本身包含类型信息,有利于优化,可以理解,但是,为什么反而有利于解释执行?
0 请登录后投票
   发表时间:2009-03-23  
nereusposeidon 写道
指令本身包含类型信息,有利于优化,可以理解,但是,为什么反而有利于解释执行?

指令本身包含类型信息对于运行时的各种操作都可以说是“有利”的,包括解释执行,也包括JIT。
形象的说,一件事你总得做,不管是编译时还是运行时,并且这件事等到运行时才做也不会带来额外的信息;把类型信息放在指令集里等于编译时做了这么件事,不放在指令集里就是非要等到运行时才能做。
相对来说,MSIL/CIL指令集里的类型信息较少,在解释运行时需要做更多的工作,执行每条指令都必须根据不同的参数类型来做进一步分发,所以效率会比较低;为了弥补这点,一般CLI实现都是采用先JIT的方式来执行方法的,这样每个方法只会在初始被调用时较慢,而不会每次调用都很慢。Portable.NET是一个例外,并不将CIL给JIT为本地代码,而是转换为它们成为CVM的中间代码然后解释执行。显然这速度是比不上CLR和Mono的。

Java/JVM对原始类型的特殊处理也不是没有代价的:Java语言严格区分了原始类型与引用类型,而在VM层次进一步区分了数组与引用类型(也就是说JVM中数组不是引用类型)。这使得Java语言里有很多很恶心的特殊规则来处理原始类型与引用类型、数组与引用类型的差异,也就是装/拆箱、特别针对数组的for-each规则等。因为int不是Object所以你甚至不能写1.toString()。在JVM上实现的其它语言有许多回避了这个问题,统一了对象模型,不区分原始类型与一般类型,但因为JVM的设计方式,这些语言实现不得不自己处理原始类型相关的问题。
已被评为好帖!
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics