Hello World
Spiga

为什么我支持托管运行时(虚拟机)

2010-07-01 03:37 by 老赵, 3492 visits

最近博客园上在炒关于C#性能的问题,其实应该说是.NET性能的问题,其中某位仁兄提出,他希望C#能够直接编译为原生代码,而不是在CLR这样一个托管运行时上执行,因为虚拟机啊,JIT什么的性能差。后来发到TL上以后,也有朋友认为,“基于虚拟机的语言都是大公司为了利益在推动,说白了就是政治”,因此“对C#提高性能的建议感到可笑,因为它本来就不是用来开发高性能程序的”,再有,“C、C++已经明确不和这些后进争所谓的‘容易开发’的头衔”,那么其他语言为什么要和C++它们比较性能呢?我是托管运行时,或者虚拟机的忠实拥护者,这里谈一下我在这方面的看法。

我并不反对编译为原生代码的语言,尤其是C语言,它的意义在于提供了一种对硬件完全控制的手段,对硬件提供了一种最直接的抽象,几乎可以映射到最终流程控制方式,因此无可替代。C++作为C语言的超集,提供了更丰富的抽象能力(如面向对象和模版化),只是语言本身过于复杂,超过了以我的智商可以承受的范围,因此我学了几次都没怎么学会,现在更是忘得差不多了。不过我认为,越来越多的语言会构建在托管平台上,而不是直接编译成原生代码。因为一个统一的托管运行时会带来很多好处。

首先,统一的运行时提供了跨平台的能力,Java便是一例典型。.NET上有mono,使用也很广泛,也有不少如Unity3DGnome DO等成功案例。Novell,包括其他一些公司也在销售基于mono的商业产品(如MonoTouchInfragistics的ASP.NET Controls组件),我本身也在两年多前就在生产环境上使用了mono,您现在看到的这个博客也是基于Ubuntu Server、mono 2.6 、Apache以及微软开源的ASP.NET MVC 2构建的。虽说从某些层面(如API兼容性)上说,mono的跨平台性远不如Java平台,但它也是一个比较成熟的执行环境,并具备相当程度的跨平台能力——尤其是在mono上开发,MS .NET上运行的时候(虽然我不建议这么做)。如今支持mono的产品、类库数不胜数,我时常调侃道,“如果您的产品不支持mono,还真不好意思和人打招呼”。只可惜,不少人都用一些“不是亲娘生的”类似的调调来否定mono,在我看来没有经过调查研究的看法只能属于“臆断”,而且更是一种FUD了。

即便退一步来说,我们不“跨操作系统”吧。有人说,.NET就支持Windows么,何必搞个虚拟机,还JIT那么麻烦。但事实上,“跨平台”并非指的是简单的“跨操作系统”,而是“跨执行环境”,如Silverlight。事实上,跨计算机体系结构本身也是种跨平台(当然,操作系统其实已经进行了一定的统一抽象了)。因此,虚拟机的目的,是为上层执行体抽象出了统一的运行环境——这其实还是跨平台,这平台不仅仅是指操作系统,整体运行环境之间的差异也是运行时所“抽象”的一部分。比如在并发环境中,不同CPU架构的流水线上的乱序方式不一样,同样的代码执行的效果就可能不同。最典型的例子,便是JVM之前的内存一致性模型控制的比较宽松,导致经典的double check模式在某些CPU上是会失败的。现在Java标准也变得严格了,和.NET CLR一样避免了Store Reordering。这意味着在某些CPU上,会在特定的地方加上Memory Barrier保证执行效果的一致性。在我看来这是更好的可移植性。C++或是C语言等实现“可移植性”的方式,往往是通过为不同环境提供不同的编译器,生成不同的结果,而且会使用“宏”等方式,在代码里写出有平台针对性的代码。

有了统一的运行时,也可以让多语言互操作更为容易,如果没有JVM或CLR,就很难像现在这么轻松地在Scala/Java/Jython/JRuby,或是C#/F#/IronPython/IronRuby,甚至是未来的语言之间进行直接地互操作,更难做到“无缝集成”了。在合适的场景下选用合适的语言,是提高生产力的重要手段。如果没有JVM平台,就很难使用Scala来代替Java这样的劣质语言,而现在Scala便能够保证充分利用Java平台上类库等积淀。

有了“多语言”,那么便会引出虚拟机的另一个作用:让语言实现者和虚拟机实现者的工作可以分离开来,各自优化。虚拟机的实现者可以尽力优化虚拟机的各种表现,为虚拟机加入各种优化措施,而无需让虚拟机的上层语言分别调整。例如JVM性能提高之后,Scala、Java、Jython、JRuby等语言的性能都可以提高,否则各种语言分别优化的代价太高了(当然某些情况还是需要特殊对待的)。要说这方面的实例,在.NET平台上有个开源的组件DLR(动态语言运行时),是在CLR上提供编写动态语言的统一辅助类库。以前它有个缺点,便是启动速度比较慢,因为动态代码的JIT耗时较长,而动态语言的很多场景是“即用即抛”的。后来,DLR增加了一个优化策略,便是一开始直接对抽象语法树直接解释执行,而执行多次之后才使用后台线程将代码JIT成原生代码。有了如此改进,基于DLR的动态语言,如IronRuby和IronPython的启动速度都提高了。

虚拟机/运行时本身可以做的优化也很多,如果真觉得性能不够,那么完全可以在运行前在本地编译成native code,这和直接从源代码变成native code从结果上看没什么区别。但是现实是,很少有人去这么做,因为这么做往往只是节省了JIT的开销,对性能提高效果不大。在不同环境中,此外还有各种优化,比如使用解释执行,而不是JIT以次节省内存消耗,或是在运行时回收JIT的代码(印象中在.NET Compact Framework里有这样的策略,求详情),或是在运行时根据代码逻辑进行二次编译。下面会谈一个例子。另一种典型的优化,一直在研究却还没有真正实现的,虚拟机便是“自动并行”。关于这点,Anders在上次的演讲中多次提到过,要实现这点还需要有各种支持,如声明式编程,提供“无副作用”标记,甚至在语言级别的支持等等。

之前那位朋友提到,C/C++已经明确不与后进语言比生产力了,后进语言也没办法和它们比较性能。对这个观点我持保留意见,因为基于虚拟机的做法,其优化空间还有很多,理论上也可以做到更为彻底,在许多情况下性能完全有超越静态编译语言的可能。这是许多人的看法,而事实也是如此,在某些场景下Java的性能也已经超过了C++。如回到上面的二次编译优化,对于性能优化也大有好处。举一个简单的例子,面向对象语言会出现很多虚方法调用(尤其是在符合一些关于设计的最佳实践时,如“基于抽象编程”),调用需方法需要查方法表找方法入口,最普通的做法就是必须每次根据对象的实际类型查找方法表,找到地址,然后调用。伪代码如下:

根据实际类型找到函数入口
调用

但是在实际执行过程中,可能有某个特定类型出现的次数特别多,甚至完全只会出现一种具体类型的实例(抽象只是为了扩展性或是单元测试等等),但因为虚方法的调用语义,我们就无法对这次调用进行内联优化等等。不过在托管的运行时中,如果发现某个特性类型出现次数特别多,则还是可能将那个类型的方法内联进来,然后只在“不是那个实例”的情况下才去查找方法入口。伪代码就是:

if (对象为不是类型A) then
    根据实际类型找到函数入口
    调用
else
    执行内联后的类型A的代码
end

类似这种的优化不是空中楼阁,它们在HotSpot(即SunOracle的JVM)是确切实现的。Hotspot的JIT,尤其是加上-server开关时,它的优化会变得十分激进,而CLR的JIT与它相比就像是静态编译器了。C++在科学运算中性能高,往往是靠大量的inline和精细资源控制,但是这说实话都还是静态的“手动优化”,如果比实际工程的真实运行情况,比如上面说的虚方法跳转,还真不见得C++可以超过托管代码。虚拟机做的则是动态优化,对于长期执行的代码甚至可能执行的越来越高效,还能够针对环境改变作出调整。总而言之,托管代码可以运用的优化策略实在太多了。随着技术发展,托管代码的速度可以进一步提高,而静态编译代码的空间就小得多了。

对此Milo Yip老大做过一些补充,他指出这方面不同的C++ compiler有不同優化方法,例如VC2008開始有的Profile-Guided Optimizations

Virtual Call Speculation - If a virtual call, or other call through a function pointer, frequently targets a certain function, a profile-guided optimization can insert a conditionally-executed direct call to the frequently-targeted function, and the direct call can be inlined.

我简单地思考了一下,从理论上说,各种优化策略都可以通过静态编译的方式写入原生代码,因此JIT能做的事情,native code理论上都能做。不过,这就意味着要在每个程序中带上“负责优化”的代码,而不光是程序的“功能代码”。用虚拟机,就意味着所有的程序都共享了虚拟机的这么一套优化机制。如果虚拟机的优化手段改进了,那么所有基于虚拟机的程序都能获利,而静态编译的程序,往往只能靠“重新编译”来得到优化了。

此外,对于面向对象语言来说,虚函数是很常见的,虚函数之间各种组合调用,分支、路径也特别多,到处都可能使用虚函数。我“猜想”,像VC这样的编译器,为每个虚函数调用之处都提供了基于profiling的内联优化是不太现实的。而且,为每个虚函数调用的地方都提供“内联”和“不内联”两种版本也不太可能。而基于虚拟机的话,它就可以动态的进行各种优化,每段JIT后的代码都可以回收再动态生成,这种优化是静态编译难以比拟的。

诚然,就目前来说,就性能方面,许多情况下还是静态编译配合手动细节优化可能获得更好的效率,但利用托管运行时获得的好处也是非常可观的,而且我也一直没有遇到过这方面的效率问题。同时,我认为托管运行时的愿景也十分现实可靠,因此就我看来,托管代码是未来趋势,除了越来越小的特定领域,越来越多的程序和语言会构建于托管平台上。事实上,正因为上面这些好处(例如独立优化),越来越多的语言也开始加入虚拟机这样的策略了。例如RubiniusPyPy等新的Ruby和Python语言实现,其实都是有个虚拟机这样的机制存在。

最后我再多说一句:我并不是说追求性能的做法不对,我也从来不会说追求性能本身没有意义。但是我不同意说“考察托管语言性能”没有意义,更是完全不同意说托管代码虚拟机“本身意义就不大”,“完全是大公司在推动”,或是“政治因素”云云。技术就是技术,这些技术上投入了无数天才的精力和创意,这不是什么“政治”之类说法就能带过的。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

57 条回复

  1. infinte
    60.166.103.*
    链接

    infinte 2010-07-01 03:41:03

    沙发?

    其实我同样很支持托管运行,指针我真的受不了……

    当年搞OI的时候就被指针弄得晕头转向

  2. 老赵
    admin
    链接

    老赵 2010-07-01 03:53:09

    @infinte

    你用C搞OI?我记得当时用Pascal搞OI的时候基本不需要指针的吧。

  3. sunli1223
    220.181.24.*
    链接

    sunli1223 2010-07-01 03:53:39

    具体环境具体分析。 虚拟机其实节约了很多开发成本,很多时候对于损失的性能是完全值得的,况且很多事我们的系统都是分布式的结合使用的。比如你用的数据库,很可能就是C语言写的。而对于系统的瓶颈的地方,你可能也会考虑使用C来实现,但是大多时候,我们还是把代码托管在虚拟平台。

  4. infinte
    60.166.103.*
    链接

    infinte 2010-07-01 03:55:02

    @老赵

    我用pascal的,不过二叉树啊,链表啊之类的肯定用指针……记得做一个平衡树(SBT)的时候,被指针弄得头都大了

  5. 老赵
    admin
    链接

    老赵 2010-07-01 03:56:54

    @infinte

    噢,好像是啊,年代太久远了……唉,我怎么就堕落了呢?当年一起搞OI的好像混的都比我好。

  6. weiwei
    114.176.248.*
    链接

    weiwei 2010-07-01 04:28:49

    讲得好多啊.作者的积累真是太厚了.不过,这些东西能说明什么问题吗.该用的人还在用,不该用的人还是不用.

  7. yuanyi_wang
    218.25.161.*
    链接

    yuanyi_wang 2010-07-01 04:37:08

    对于复杂的应用程序,托管代码能更容易的取得良好的性能,毕竟在这个硬件很便宜的时代,托管代码更容易的造出一个砸机器就取得高性能的程序。我觉得,这个对于很多公司更为重要。当然,关键的计算密集型算法和硬件控制功能还是得依赖与C甚至是汇编。 总结起来就是:具体问题具体分析,该用啥就用啥。

  8. gebenxiang
    220.248.45.*
    链接

    gebenxiang 2010-07-01 04:40:19

    mips公司为android dalvik jvm做了个mips的实现, 就可以在mips android上直接跑arm android上以编译的程序。这多美妙?

    vm有很多奇妙的应用。比如有人通过虚拟机把Doom游戏直接跑在adobe flash的VM上

  9. shitmono
    134.159.152.*
    链接

    shitmono 2010-07-01 05:12:02

    博主可以老实说说盛大有什么产品用.net开发的吗?如果没有,你能说服他们吗?如果说服不了,你还会在里面呆下去吗?

  10. 老赵
    admin
    链接

    老赵 2010-07-01 05:24:05

    @shitmomo

    如果是已经发布的产品,我知道起点是用.NET开发的,现有的产品是估计不会迁移到.NET上。我这边开发新产品时无所谓用什么技术,就看谁提出的,谁想用什么。我的东西是.NET和*nix都有,还有一些产品的后端用的是.NET,具体是什么还不能多说。

    至于如果有什么情况逼的我.NET哪儿都不能用,那么我就会看有没有我感兴趣的东西。如果没有的话那么就可能不呆的,不过我又不是非.NET不做的人,我对许多东西都感兴趣。

  11. 老赵
    admin
    链接

    老赵 2010-07-01 05:26:50

    @weiwei: 讲得好多啊.作者的积累真是太厚了.不过,这些东西能说明什么问题吗.该用的人还在用,不该用的人还是不用.

    对于听什么都无所谓,或是坚持自己什么都听不进去的人来说,自然没有多少作用。不过我相信总有愿意思考讨论的人,我写文章是表达自己看法,不是强求别人接受,本来这些就是各方发表自己看法然后再总结的。

  12. 老赵
    admin
    链接

    老赵 2010-07-01 05:36:09

    @yuanyi_wang: 对于复杂的应用程序,托管代码能更容易的取得良好的性能,毕竟在这个硬件很便宜的时代,托管代码更容易的造出一个砸机器就取得高性能的程序。

    我的看法是不仅是“靠砸机器取得高性能”的场景。

    其实现在原生代码性能更高,基本还是高在“细节”上,如果程序员可以得到足够的信息,那么自然可以进行手动优化得到更好的效率。不过,如果出现某些优化是复杂度很高,几乎人力不可控的情况,那么托管平台的优势就出来了。其实普通人写汇编还真不一定有C语言性能高,也是同样的道理。比按照规则进行优化,机器比程序员要强大无数倍。

    而且,对于纯计算密集型的东西来说,因为规则就这么点,人力可以涉入优化。但是如果是复杂的程序,比如我文章里写的虚方法的内联调用,甚至要根据长期结果进行自适应的话,就几乎一定是托管代码了。

  13. 链接

    秋实 2010-07-01 05:48:20

    Reflection等一批概念也是建立在Runtime基础之上的吧,提高生产力是一定的,而改变编程方式应该属于质变了

  14. 链接

    mfjt55 2010-07-01 06:04:32

    对此Milo Yip老大做过一些补充,一些补充上的链接好像打不开。

  15. DJ
    183.3.171.*
    链接

    DJ 2010-07-01 07:15:25

    Profile-Guided Optimizations那个链接写错了吧.

  16. 链接

    twty1988 2010-07-01 07:25:40

    我觉得托管运行时(虚拟机)主要还是解决了硬件的细节问题,让程序员把精力集中的业务上。

  17. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-01 07:32:00

    @老赵

    我感觉老赵你是在做理论探讨,而firelong则是在说实际应用效果。

    理论上托管运行时速度可以达到,并不等于实际中达到了。

    firelong其实说的就是现在.net在客户端软件开发中不好用。

  18. 老赵
    admin
    链接

    老赵 2010-07-01 08:12:02

    @mcpssx

    我不觉得他在说实际效果,他一直在说理论,例如“元数据一定导致性能不可接受”一样。说起来我还给了实际例证呢,都是切实证据可以说明托管平台的优势的。他说XX软件“一定也做过测试”,证明托管平台性能不行等等,但我问他“有没有报告可看”的时候,他的回复是“这不是明摆着的吗,还需要看什么”之类的话。关于性能方面,过一段时间我会补充一些实验,现在手上有一些profiling结果,但还没仔细分析……

    其实我也很感兴趣到底他遇到了什么问题,如果能真正拿出来分析一下,说不定也就可以解决了,到底是运行机制的硬伤还是程序写的有问题,都可以清楚。别人给Profiling数据,他说这数据不全面,但又不给出自己任何Profiling结果,所以现在这样倒还真是什么都说不清了。

  19. 老赵
    admin
    链接

    老赵 2010-07-01 08:14:01

    @DJ

    谢谢,改好了。

  20. avlee
    119.62.30.*
    链接

    avlee 2010-07-01 08:15:06

    某些情况下性能优于C++应该是实际情况,关键是这种情况就不要使用C++了,现在都混合编程,干嘛要一棵树抱着死呢?其实有些人可能想表达的初衷不要是一味的追求纯C#纯java。

  21. Paul Shen
    117.84.247.*
    链接

    Paul Shen 2010-07-01 08:38:22

    千万不要忽视理论。 有了理论才能解决实际问题。

  22. Paul Shen
    117.84.247.*
    链接

    Paul Shen 2010-07-01 08:42:31

    @老赵

    请问能达到C+操作系统的水平吗?

  23. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-01 08:47:12

    @老赵

    firelong是先有了实际效果然后去考察为什么慢。反对firelong论证C#不慢的其实理由并不充分。

    大部分说C#不慢的实际上都是拿函数级代码说事,比如渲染啊,光照啊,其实这个不用测,网上有专门的比较各种语言性能的网站,从百行代码级别看,java、C#运算速度确实不算慢。

    但在实际应用中就有问题了,比如飞信慢,不能说是什么架构问题,难道每个C++项目组都很精通架构吗?那么很慢的C++程序,我们见到过几个呢?

    再比如在简单代码评测中,C#, java的速度绝对要比ActionScript快一个级别,但是实际上Flash和Swing应用的感受,相信大家都知道,这绝不是因为flash程序员比java程序员架构架的好。

    firelong是从.net体系入手论证C#慢,而不是论证C#的i = i + 1的速度不可接受。

  24. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-01 09:15:41

    1、按照函数级别的评测,那C#、java运算速度,确实可以达到C++级别。 但实际上完全不是这样,否则微软何不用C++/CLI马上把SQLServer,Office,IE现有代码先统统.net化呢?接下来他就可以C#开发新功能了。

    2、“统一的运行时提供了跨平台的能力”,问题是实现跨平台的关键是API 1)微软的.net api是只为windows考虑的,很可能带有windows的独有特性 2)微软一贯有不断变换api的本性,一贯有把跟随者拖垮的历史。 mono现在是可以跨平台,问题就是他对java的优势何在呢?

    而老赵列举的【使用也很广泛,也有不少如Unity3D,Gnome DO等成功案例。】实际上这些是游戏开发者或者专门平台上的开发者,其实是把mono作为一个有类型的脚本语言做二次开发用,这时候二次开发者并不真么使用.net的api,而是使用游戏或平台本身提供的功能调用。

  25. 老赵
    admin
    链接

    老赵 2010-07-01 09:50:40

    @mcpssx

    其实firelong的问题已经有很多人指出了,他也是根据自己的问题来进行所谓的“论证”,最多也只是个孤证,甚至根本不能算是论证,他只是说出这些架构在性能上可能出现的问题(这点谁都知道),但是他故意忽略了优点,更是武断地说这些问题很“严重”。那么到底有多严重?他不给任何说法了。简单地说,他的确是从“体系结构”入手了,但是没有“论证”。

    事实上,谁主张谁举证,这个是标准流程吧?但是他不给出点能够说明问题的例证,教谁都没法充分应对。能够给出特定环境下的几个测试,我觉得已经很够意思了,也只能做到这点了。其实我觉得你是同意他的看法的,我认为你也可以帮他举证,例如给点更充分的证据,而不仅仅是推断。这方面讨论好了也是挺有价值的。

    至于你说的“XXX为什么不重写”,这很没理由,大型应用根本不可能重写,你不能说这是技术方面的原因。而且事实上你可以发现,在Office,SQL Server,IE,Windows Live和Expressions套件,还有VS等程序里面,托管代码用的已经越来越多了,甚至完全就用.NET开发了。

    .NET API有没有Windows的特征,这个我不清楚,我还是只能说,你偏要如此臆断我也没法回应。我的看法是,Java既然可以兼容,我不觉得mono哪里没法兼容,除非是操作系统的能力上有很大冲突,比如用Windows可以实现的某一个功能,Linux上就根本没法实现。还有.NET的兼容性是相当好的,基本是无痛升级(上次大众点评也这么说)。框架设计团队还写了一本书,你可以看看。

    你最后举得例子,你说的把mono当引擎用,而不是利用了.NET的API,首先我没想明白怎么可以摆脱.NET的API来使用mono,其次Unity3D,Second Life是使用mono做脚本引擎,而Gnome Do是个标准的客户端程序了,后面我说的MonoTouch,ASP.NET控件都是直接使用.NET的API。

    当然,你一定要说mono的跨平台做不到Java这样,这点我也认同,我也已经说了,我是把mono看作一个成熟的运行时来看待,而并不一定追求它跨平台做的有多好。不过我也想指出,现在同时支持MS .NET和mono的程序、语言、类库也已经有许多了,说明它至少在一定程度上说也“足够好”了。

  26. Paul Shen
    117.84.247.*
    链接

    Paul Shen 2010-07-01 10:20:44

    我还是用C吧,阿门

  27. 链接

    Ivony 2010-07-01 10:28:49

    其实了几天了,真的没看到所谓的反对firelong阵营这边有谁说C#快了,顶多是证明“不慢”,C#在大多数应用下性能不如native从来没有人去否认过。“C#很快”这个大帽子本来就是强加在所谓的“老赵们”头上的,然后再拉出去批斗。

    既然说了是实际应用中了,那问题就复杂了,就不可能简单的说,因为C#所以慢,或者,因为JIT所以慢,因为元数据所以慢。这些都是毫无根据的臆断,说白了就是梦话。然后再偷换概念,C#慢是“众所周知”的,所以C#体系架构就有问题了,这也是“众所周知”的,微软的路就走错了,这也是“众所周知”的。这不是扯淡么?

    如果C#根本(体系架构上)就是有问题的,是无论如何也搞不好的,那怎么去说明在特定情况下C#就性能差不多,甚至更好呢?所以问题不会出在根本上。也不可能如firelong那样把C#断手废脚就能快了。

    顺便回答几个问题:

    1. 为什么没看到几个很慢的C++程序。
      答:快和慢是相对而言的,在一个最快就是C++的编译的native code的软件环境下讨论为什么没有比C++快的程序是毫无意义的。因为Windows API不是汇编的,现在也没有人用汇编去写Windows Application。我们假设现在Windows API撤掉,全部用.NET提供,我看在Windows下C++也未必快的起来。就像DOS时代的API是中断,C++未必比汇编性能好。

    2. 为什么微软不把以前的软件都用.NET重写,这样就可以用.NET来开发新功能了。
      答:用.NET重写不是用.NET开发新功能的必要条件。VS、SQL、Office、Windows都不是.NET写的,但这不妨碍它们可以用.NET扩展功能,至于VS,现在已经用WPF做界面了。这么多年了磁盘的引导扇区和BIOS也不是C++写的,为什么不用C++去重写一下?

    3. mono或.NET对Java优势何在?
      答:Mono只是提供了多一种可能。.NET本来的定位就是替代Windows API,也没打算在Unix上与Java一较高下。难道微软把Java从Windows平台上赶出去了不是一种胜利么,至少我见到的跑在Windows平台上的.NET应用比Java的多。再说了,如果Java占领了其他所有的桌面平台,但是却被从全球80%以上的桌面(Windows)中赶了出去(假设)。那到底是谁赢谁输?对于非桌面,.NET 里面与Windows平台捆绑不可分割的部分,除了UI又还有多少呢?

    结语:废话这么多,不是为了吵架,只是想试试老赵的这个博客的有序列表的样子。

  28. 老赵
    admin
    链接

    老赵 2010-07-01 10:34:37

    @Ivony: 废话这么多,不是为了吵架,只是想试试老赵的这个博客的有序列表的样子。

    唉,我不会CSS,样式调不好看。

  29. 链接

    miloyip 2010-07-01 14:08:51

    本來一早都想在TL回的,但最近TL比較亂,就在此討論吧。

    C++或是C语言等实现“可移植性”的方式,往往是通过为不同环境提供不同的编译器,生成不同的结果,而且会使用“宏”等方式,在代码里写出有平台针对性的代码。

    其實這只是平台抽象的地點不同。我也可以改寫為:

    C#或是F#語言等實現「可移植性」的方式,往往是通過為不同環境提供不同的VM,生成不同的JIT後原生代碼。

    採用C/C++標準的代碼,本身是跨平台的(雖然還要注意CPU架構,例如sizeof(int)和byte order)。一般的問題是,C/C++的標準庫提供的東西太跨平台,缺乏很多常用的功能,例如GUI。但若採用如Qt或wxWidget等庫,還是可以簡單地寫跨平台的GUI,在應用程序的代碼中不需要用宏作跨平台之用。OpenGL也是一個「理論上」跨平台的C API。但通常VM提供的庫比較標準化,而C/C++則是多元化。

    这意味着在某些CPU上,会在特定的地方加上Memory Barrier保证执行效果的一致性。在我看来这是更好的可移植性。 C/C++標準中,並沒有多綫程。所以C/C++在這方面的移植性基本上可以忽略不談。但在性能上,由於C/C++必須使用OS提供的功能,所以可以選擇該OS效能較好的同步機制。但要用C/C++寫出正確且高效的多綫程程序,一般會比C#難(OpenMP除外)。

    看到本文指向之前一篇文章(在某些场景下Java的性能也已经超过了C++),有關pointer aliasing的C++和Java性能問題。C++編譯器提供一些聲明方式來解決,例如VC有_declspec(restrict)、_declspec(noalias)和__restrict。

    不過這是都是由於C/C++接近CPU,有pointer機制才會產生這個問題。在其他語言中,可以保證兩個數組不會指向同一個地址。C/C++的難點也在於此,必須更了解低層,才能寫出高性能的實現。而使用VM,則有時候控制權不在程序員手中。這都是雙面刃。

    而且,为每个虚函数调用的地方都提供“内联”和“不内联”两种版本也不太可能。

    事實上,就算不使用profile guided optimization,C++對於一個虛函數,是分開虛調用和非虛調用的。典型的例子是在virtual destructor中,調用父類的destructor,父類的destructor是可以inline進子類的destructor中。常說C++的EXE大,有很大部份原因就是因為inline(及template)所致的。所以我認為,說C++不可能提供兩種版本,証證是不太充份。

    而基于虚拟机的话,它就可以动态的进行各种优化,每段JIT后的代码都可以回收再动态生成,这种优化是静态编译难以比拟的。

    這個概念其實像profile guided optimization,不過是動態進行。但兩者皆有共同缺點。它們都是估計將來的輸入數據特性相近,所以才可以透過統計方式提高期望的(expected)效能。但無論靜態或動態,都難以估計將來的輸入數據是否和profile的接近。動態的話,有可能可以進行適應性調整,但這種算法也不一定能帶來效能提升,反而會有profiling和JIT的開銷。

    但總括而言,我也認同趙姐夫的說法。我認為VM是一個技術歷史上的突破,對多個因素(包括性能、安全性、開發速度、可維護性等等等等)有適當的平衡。C/C++是適合某些需要極端性能並和硬件打交道的應用(OS、web/database server、game)、或性能十分有限的系統(embedded、mobile)。一舨的應用程序,客戶和硬件的需求變化較多,使用VM很多時候較為合適。反而是最近測試過一些動態語言,雖然有更大的動態功能,但是要換取幾個性能數量級。這更讓我懷疑純解譯型的語言實現,適用時機是否足夠。

  30. live41
    58.249.27.*
    链接

    live41 2010-07-01 14:28:13

    为什么微软不直接把代码生成到标准的PE格式?

    一定要楞个IL来执行,莫非是为了好让最后通过IL在各语言之间转换?

  31. clotho
    58.249.27.*
    链接

    clotho 2010-07-01 17:07:21

    现在的程序,实际上没有几个是专门为跨平台而设计..

    既要在win运行,又要在linux运行的,这样的构想除非是很多地方用到,否则争论虚拟机是浪费时间..

    像C语言要用到线程,完成端口(linux下用epoll)等一些系统特有的特性,也不是跨平台的,最后还是要移植..

    先不讨论.net和jre慢不慢,我只是觉得弄个虚拟机说目的是为了跨平台有点废..

    因为跨平台的设计少之又少,特别是在中国..

  32. clotho
    58.249.27.*
    链接

    clotho 2010-07-01 17:15:43

    上面的话逻辑有问题.. 我要表达的应该"跨平台的.net程序很少",

    我只是见过在win下写java代码,然后拿去linux重新编译再运行..

    很少见到人在win下写C#代码,然后拿去linux下用mono重新编译运行..

    如果有人这么做,是我孤陋寡闻..

  33. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 00:50:26

    @老赵

    firelong的论述起因很清楚,应该是实践中遇到了问题而反思的。

    能够给出特定环境下的几个测试,我觉得已经很够意思了,也只能做到这点了。其实我觉得你是同意他的看法的,我认为你也可以帮他举证,例如给点更充分的证据,而不仅仅是推断。这方面讨论好了也是挺有价值的。

    1、特定环境的测试是不能说明问题的,我已经说过了,在这种加减乘除的测试中,java的速度绝对比actionscript快一个数量级,但是flash和swing的给用户的感受也是很明显的。这时候你应该先从客户感受定性入手,而不是反过来用加减乘除测试来证明swing比flash快。

    2、其实举证也很简单,比如飞信,他用.net和C++的时候,架构师变了吗? 在举个例子就是EverNote,不知道你听说过没有,这是一个知识管理和网页捕捉工具,他的3.1是c++的,3.5是.net的,功能基本一样,比较一下反应速度和内存消耗,就很明显了。

    .NET API有没有Windows的特征,这个我不清楚,我还是只能说,你偏要如此臆断我也没法回应。我的看法是,Java既然可以兼容,我不觉得mono哪里没法兼容,除非是操作系统的能力上有很大冲突,比如用Windows可以实现的某一个功能,Linux上就根本没法实现。还有.NET的兼容性是相当好的,基本是无痛升级(上次大众点评也这么说)。框架设计团队还写了一本书,你可以看看。

    1、这个很简单啊,比如wpf就依赖directX,再比如说iocp,所以mono团队可以很快实现c# 4.0语法的功能,但是迄今还不支持wpf吧

    2、java可以兼容是因为预先就考虑了跨平台问题,比如说有个File.seperator, .net需要考虑这个吗?

    他出的每个版本的时候,必然同时出各个平台功能相同的版本,相反mono现在的api和windows的一样吗?

    你最后举得例子,你说的把mono当引擎用,而不是利用了.NET的API,首先我没想明白怎么可以摆脱.NET的API来使用mono,其次Unity3D,Second Life是使用mono做脚本引擎,而Gnome Do是个标准的客户端程序了,后面我说的MonoTouch,ASP.NET控件都是直接使用.NET的API。

    1、因为作为游戏平台的脚本语言,大部分时间是不用调用系统的api的。比如说winform, wpf, tcp都不需要使用,你见过哪个游戏脚本会使用系统层的api来绘制界面的?游戏脚本大都是在控制游戏世界中的对象。

    2、gnomo do这个名字就很清楚了,他实际上调用gnome的api,他需要使用winform吗?他能在windows上用吗?

  34. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 01:10:59

    @Ivony

    其实了几天了,真的没看到所谓的反对firelong阵营这边有谁说C#快了,顶多是证明“不慢”,C#在大多数应用下性能不如native从来没有人去否认过。“C#很快”这个大帽子本来就是强加在所谓的“老赵们”头上的,然后再拉出去批斗。 既然说了是实际应用中了,那问题就复杂了,

    其实问题一点不复杂,就跟当年说swing慢一样,就是用户感受太慢。 你去下一个evernote 3.1和3.5比较一下,就知道了

    为什么没看到几个很慢的C++程序。 答:快和慢是相对而言的,在一个最快就是C++的编译的native code的软件环境下讨论为什么没有比C++快的程序是毫无意义的。因为Windows API不是汇编的,现在也没有人用汇编去写Windows Application。我们假设现在Windows API撤掉,全部用.NET提供,我看在Windows下C++也未必快的起来。就像DOS时代的API是中断,C++未必比汇编性能好。

    这里比较的快慢,并不是讨论C++最快的问题,而是用户体验慢的问题。Flash的actionscript性能就不如java,但是没几个人说flash不能接受。

    为什么微软不把以前的软件都用.NET重写,这样就可以用.NET来开发新功能了。 答:用.NET重写不是用.NET开发新功能的必要条件。VS、SQL、Office、Windows都不是.NET写的,但这不妨碍它们可以用.NET扩展功能,至于VS,现在已经用WPF做界面了。这么多年了磁盘的引导扇区和BIOS也不是C++写的,为什么不用C++去重写一下?

    1、我举个简单例子,迄今为止,office还不支持VSTA,还是VBA。而VSTO就麻烦很多。虽然C#可以扩展native C++,但是总是麻烦吧?

    2、微软不是不想,而是失败了,这个李开复的回忆里不是说过了吗?

    3、因为你列举的bios啥的,都是系统层的功能,并不适合C#,而SQLServer,Office都是应用软件

    mono或.NET对Java优势何在? 答:Mono只是提供了多一种可能。.NET本来的定位就是替代Windows API,也没打算在Unix上与Java一较高下。难道微软把Java从Windows平台上赶出去了不是一种胜利么,至少我见到的跑在Windows平台上的.NET应用比Java的多。再说了,如果Java占领了其他所有的桌面平台,但是却被从全球80%以上的桌面(Windows)中赶了出去(假设)。那到底是谁赢谁输?对于非桌面,.NET 里面与Windows平台捆绑不可分割的部分,除了UI又还有多少呢?

    1、你做.net自然见到的.net应用比java多了。

    2、没有.net之前,java也没有占领windows桌面平台。

    3、现在.net也没有占领windows桌面平台

    你现在的桌面上有几个是.net软件?

  35. 老赵
    admin
    链接

    老赵 2010-07-02 02:06:40

    @mcpssx

    我先谈几点明确的,关于跨平台的。

    1. Java里的异步IO可以在不同平台上利用起IOCP和epoll和kqueue,mono要用也可以用。
    2. .NET的API也是考虑到跨平台的,包括endian,包括Path.PathSeperator等等
    3. WPF利用DirectX,并不是直接暴露出DirectX的接口,只是用于硬件加速渲染而已,mono的话依赖OpenGL之类的不就可以了。
    4. 核心框架的话,mono的api是和MS .NET一样的,只是一些不太用的函数没有实现,但是它们都是平台无关的,包括一些没有实现的新框架,我估计mono只是没有意愿、精力等去实现而已。

    所以,还是差不多的说法,有没有Windows上可以做好但是Linux等平台上做不好的工作呢?

  36. 老赵
    admin
    链接

    老赵 2010-07-02 02:14:54

    @clotho: 我只是见过在win下写java代码,然后拿去linux重新编译再运行..很少见到人在win下写C#代码,然后拿去linux下用mono重新编译运行..

    国内mono用的很少,自然不会在win下写C#,到Linux下去编译。国外的话,关注一下一些开发者大会,或是CodeBetter这样的社区,就会发现很多人用Mac写C#代码,然后运行部署在Win下。这是因为:

    1. .NET程序毕竟大部分还是部署在Win下的。
    2. 写mono部署到.net上基本不会有问题,mono实现的api是.net的子集,当然是足够用的子集。
  37. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 02:33:49

    @老赵

    关于跨平台,

    1、你那种跨平台就变成了wine式的跨平台,java、qt的跨平台是首先终合考虑的,比如swing,nio啥的,首先会抽象出一个子集。而微软本来就不是为跨windows准备的,结果就变成了像wine那样模拟api.

    2、endian之类主要是因为通信可能会与其他os的系统通信,还有一些是明显的windows特征的,比如说.net在进程间通信中有命名管道 NamedPipeNative.CreateNamedPipe之类的明显具有windows特性的东西。

    WPF利用DirectX,并不是直接暴露出DirectX的接口,只是用于硬件加速渲染而已,mono的话依赖OpenGL之类的不就可以了。

    所以,还是差不多的说法,有没有Windows上可以做好但是Linux等平台上做不好的工作呢?

    你说的这两个其实是同一个问题,因为微软其实就是靠【区别】来战胜别人的,如果真的如你所说,api都一样了,

    那还用windows干什么呢?windows操作系统的意义何在?

    所以微软一定会让他不同的,让其他平台的开发者总是无法模拟全。

    看这个新闻

    微软曾通过升级组件和正版增值验证组件(WGA)对在Wine中运行的应用进行阻挠。微软的发言人表示,其Windows Genuine Advantage(WGA)认证工具将会辨认Wine用户,因此只有运行真正正版的Windows的用户才能下载升级和附加工具。

    现在mono只不过是没有壮大而已,所以微软还利用它来打击java之类的,一旦真的如你说的都一样的,微软一定会想办法让mono无法实现。

    其实,这个历史上就发生过的,borland公司就是前车之鉴。

    但是让Symantec和Watcom C/C 大吃一惊的是Microsoft使用的MFC居然比它们的版本高出了一个版本(1.x对2.x),而且新版本的MFC包含了完整的OLE支持能力。而 Borland虽然也有OCF,但是仍然不敌新版MFC中的OLE能力。由于当时几乎所有的应用程序都需要支持OLE,但是却只有使用Visual C/C 最新的版本才能够开发完整 OLE能力的应用程序,因此不管OLE到底有没有用,反正先加入再说。因此市场上的情势很快的就发生了巨大的变化,几乎大部份的应用程序开发因为OLE的原因都选择使用Visual C/C ,Symantec和Watcom军团很快的就败阵下来。

    至于Borland C/C 4.5虽然是一流的产品,如果没有OLE的因素,Visual C/C 新版本真的并没有比4.5好。虽然4.5也有OCF,但是在市场上只有Borland和Novell, WordPerfect选择使用OCF,在和Microsoft的Visual C/C 经过将近一年的缠斗之后,其它大部份的厂商都选择了Microsoft的MFC 2.x版,真是形势比人强。基本上 OCF的架构真的是个好东西,只是OCF无法完整的支持OLE,因为OLE的发展是掌握在 Microsoft手中,因此虽然OCF的架构良好,终究在功能上不及对手。

    在windows上都搞不定,何况跨平台模拟windows的api

  38. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 02:40:09

    @老赵

    看了你的"单链表与List究竟哪个遍历速度快?",我有一个疑问, 单链表访问next是使用的public Node Next;直接的字段访问,而list却使用的[]访问操作符,这应该是一次函数调用吧?

    为什么不直接比较数组呢?或者链表的next字段使用属性语法来访问呢?

  39. 老赵
    admin
    链接

    老赵 2010-07-02 04:18:15

    @mcpssx:

    如果你要基于开发跨平台应用,与Windows相关的特性本来就不会去用,所以mono即便不支持也没有关系。其实你说的并不是mono的问题,而是任何跨平台的问题了,即便是Java,它也没有办法利用起某个操作系统的完全功能,这简直是跨平台的天然障碍。当然,是理论上的障碍,是否影响使用,这是另一回事情。比如CentOS的N多企业特性是好,但是在大部分情况下应用用不着,那我还是情愿用Ubuntu(最近在和人讨论这个,所以随便差一句,呵呵)。

    我还是这句话:Java可以统一,mono没什么理由统一不了。事实上,.NET里面绝大部分API是完全跨平台的,你来以偏概全就没有意思。我觉得你说了那么都是还是在臆断,mono的实际情况如何,我用过。无数程序也是支持mono的,它们也完全OK。

    至于Borland什么的,这些的确是真实历史事件,永远落人口舌,我也没法去解释说它们没有发生过。不过我想说,其实你这种做法也是在FUD么,呵呵。拿N年前发生的事情,用于攻击现在,虽然你可能觉得有道理,但我觉得很没意思。

  40. 老赵
    admin
    链接

    老赵 2010-07-02 04:22:09

    @mcpssx: 看了你的"单链表与List究竟哪个遍历速度快?",我有一个疑问, 单链表访问next是使用的public Node Next;直接的字段访问,而list却使用的[]访问操作符,这应该是一次函数调用吧?为什么不直接比较数组呢?或者链表的next字段使用属性语法来访问呢?

    用List是因为firelong说List,而不是说数组,数组在for加下标访问的时候会有优化,性能比List高,List没有优化。当然就算数组有性能提高,也只高了一点点中的一点点,完全不是firelong所说的“远低于”或是“严重影响”之类的。还有Node.Next用属性结果也一样,JIT会做内联的。

    其实我写这文章的目的,倒不是真想说明链表List哪个快,这个大家心里都有数,根本不会有大不了的影响。我更多是想指出firelong在讨论问题上的毛病,比如信口开河什么的。

  41. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 04:56:57

    @老赵

    我还是这句话:Java可以统一,mono没什么理由统一不了。

    不要忘了,.net起源于j++,而j++就是起源于要跟java不统一。 能不能统一,首先就是一个商业问题, 微软的根基是windows,office,微软有充分的理由要防止其他平台的api跟它统一。 微软为什么不很好的支持posix,很简单,这样大家都用posix写程序了,这些程序就可以方便的移植到其他os。 微软很多东西都另搞一套,比如说不鼓励opengl,而另搞directx,winsocket一定加入了微软自己的一套扩展。

    我还是这句话:Java可以统一,mono没什么理由统一不了。事实上,.NET里面绝大部分API是完全跨平台的,你来以偏概全就没有意思。我觉得你说了那么都是还是在臆断,mono的实际情况如何,我用过,我猜你没有用过?

    实际情况就是没有统一嘛,java现在就是统一的,而.net现在并没有统一,理论上wine就可以统一,wine时间很长了吧?那现在你在wine下运行程序就没有问题吗?如果wine没有问题,就根本不用开发mono,直接把微软的framework拷过来不就行了?

    至于Borland什么的,这些的确是真实历史事件,永远落人口舌,我也没法去解释说它们没有发生过。不过我想说,其实你这种做法也是在FUD么,呵呵。拿N年前发生的事情,用于攻击现在,虽然你可能觉得有道理,但我觉得很没意思。

    这个是由微软的本性决定的,因为他的主要利润来自windows和office。

    再举个例子,就是IE的发展 1、ie当年推过vbscript的,只是没有成功,微软总是希望在平台中加入自己独有的东西,就可以限制用户向其他平台转移,扩大自己平台的影响。 2、微软为什么对ie的发展不热心,因为html本身就是一种跨平台可移植的ui。

  42. 链接

    Ivony 2010-07-02 05:27:35

    Java那种NC的架构我从第一天就不喜欢微软跟他统一。。。。

    直到今天,我都不满意微软要遵循W3C标准,看看那个NC的组织有异于地球人的想法和树懒般的效率吧。。。。。如果都遵循微软的标准,世界清净很多。这算不算微软被陷害的一个实例?

    我想程序员还是应该选择对的,选择自己喜欢的,不要过多的去讨论什么阴谋、商业、背景。BC的确做的比MC好,这一点我不否认,所以大家都用BC,很少用MC吧,至于你说的OLE什么的,个人感觉还是以偏概全。如果现在VS还是以前MC那个破样子,支持.NET我也不用。

  43. 老赵
    admin
    链接

    老赵 2010-07-02 05:50:45

    @mcpssx

    我前面说过了,mono没有统一不是因为统一不了,而且也不需要彻底统一,只要平台无关部分统一就行了。如果希望利用mono跨平台,程序员会知道哪部分平台相关的功能是不能用,或者说是不应该用的。事实上这样的限制并没有给跨平台的.net开发人员造成什么阻碍。

    wine不是一个好例子,它的要求比mono或Java这样平台高多了,mono和Java这样的跨平台追求的只是“表现一致”,这相对容易许多。而wine涉及的底层和细节过多,从一开始就注定是十分困难的。如果Java的跨平台做法和wine一样,那么它也是很难成功的。

  44. 链接

    slicelee 2010-07-02 06:53:50

    Android的成功说明了什么?谷哥弄的那个可不是为了跨平台,最多是为了跨硬件架构,ARM,X86,MIPS最好都能用上。 记得WP7最先的展示还不太让人满意,不过最近看到的真机视频操作的响应和流畅度都和IP伯仲之间了,至少在硬件保证的情况下性能不是问题了。 这两个都算很典型的例子,而且手机还是需要非常注重性能的,呵呵。

    最后的问题就是C#理论来理论去基础好像都没问题,但Winform很多都比较悲剧,WPF的资源消耗更是吓人,这也确实是事实,除了微软自己的Expression Studio等做得优秀点。

    但性能差的根源如何避免如何优化,却没有能够真正的有理有据的来说明,winform进军桌面除了快速开发和C++,dephi比起来没有自己特有的优势,而WPF在呈现方面的优势是很诱人的,要进军桌面,就现在大家用的电脑来说,探讨性能的优化还是很重要的。

    而且现在的Net程序员对算法对性能对计算机硬件架构体系的认识都很糟糕,我作为一个糟糕的Net程序员,看到自己过去的糟糕的代码,甚至连算法都谈不上调用现成的东西拐了几个弯来达到自己的需求比比皆是,博客看多了更觉得现在的代码一如既往的糟糕,看得越多越觉得糟糕。 不过可喜的是糟糕的代码一样满足了客户的需求,这就是Net吧,但WPF这些要进军桌面就不得不有所突破了。

  45. mcpssx
    59.175.192.*
    链接

    mcpssx 2010-07-02 07:05:32

    @Ivony

    直到今天,我都不满意微软要遵循W3C标准,看看那个NC的组织有异于地球人的想法和树懒般的效率吧。。。。。如果都遵循微软的标准,世界清净很多。这算不算微软被陷害的一个实例?

    1、微软对web有本能的抵抗,所以ie多年不发展,微软对web的积极性不高,他实际是被迫加入这个战场的

    3、没有人能跟随微软的标准,除了微软自己

    1)微软会不断变换标准,不断抛弃,比如说vb6曾经可以开发dhtml程序,后来就没有下文了。微软曾经推出过HTA,但是由于担心影响桌面软件,被终止了。要是现在让微软一家来定,估计就只有wpf浏览器了。

    html,javascript的延续性要好的多。

    2)微软的标准都是非常复杂的,而且他有先发优势,没有人能跟得上,最后其实只有微软一家能实现。比如说borland一贯跟着微软,最后完蛋,而Qt、GTK+反而活的很好,borland公司的技术能力绝对不比Qt公司差。

  46. 四有青年
    210.13.101.*
    链接

    四有青年 2010-07-02 07:55:06

    很久没看到这样营养丰富的文章了,分析的很细致

  47. anoter_guest
    148.87.19.*
    链接

    anoter_guest 2010-07-03 08:47:44

    解释“跨平台”那一段,为什么不从ABI和ISA的角度出发来说呢?那样该会有多么的清晰和明白

  48. 链接

    xiaotie 2010-07-04 11:02:04

    @mcpssx

    C#,Java,ActionScript3性能是一个级别的,ActionScript略慢,慢约20%左右。这个我验证过多次。ActionScript3和ActionScript2的性能据说不是一个级别的,前者据说快10倍以上。不过我怀疑这个结果,但没验证过(没验证的意义)。如果全部用ActionScript的动态特性写出的程序,当然就是动态语言性能那种档次了,如果用它的静态特性写出的程序性能就和C#,Java近似一样了。

  49. 链接

    xiaotie 2010-07-04 11:13:45

    @mcpssx

    特定环境的测试是不能说明问题的,我已经说过了,在这种加减乘除的测试中,java的速度绝对比actionscript快一个数量级,但是flash和swing的给用户的感受也是很明显的。这时候你应该先从客户感受定性入手,而不是反过来用加减乘除测试来证明swing比flash快

    不要道听途说。actionscript 1.0, 2.0 和 3.0 之间的差异比 从c到c++到c#之间的差异都大。完全就不是一种语言。单说actionscript不说版本就类似于说“C、C++或C#”?加减乘除的测试,actionscript 3 和 c# 是一个数量级的,甚至浮点计算,actionscript 3 比 c#还要快一点点。

  50. mcpssx
    113.57.9.*
    链接

    mcpssx 2010-07-04 11:44:11

    @xiaotie

    你说的也可能我记错了, 不过我说的用户比较flash和swing程序感觉的时候, 显然还没有有静态类型声明的actionscript3。

    早在as3出来之前,flash给用户的感觉就比applet好。

  51. mcpssx
    113.57.9.*
    链接

    mcpssx 2010-07-04 11:51:36

    我又查了一下,http://space.baidu.com/lewutian/blog/item/fd5cda363139e9d6a3cc2b9c.html

    一段时间以前,创建了一个针对Flash和Sliverlight的简单性能测试,同样可以用于JavaFX版本。这里有一些从我的笔记本电脑在增加输入数据10倍时候的性能数据。

    Technology                         Time
    
    JavaFX 1.0                         3.963s
    Silverlight 2 C#                   4.257s
    Flash 10                           27.840s
    Javascript, Internet Explorer 7    ~20times slower than Chrome *
    Javascript, Chrome                 22.989s
    Java 6                             3.948s
    Java 6, interpreted                22.973s
    

    以上是最好的4-5次运行结果

  52. 链接

    xiaotie 2010-07-04 12:34:31

    我错了。M个月前测了一次,C#和as3差不多。N个月前测一次,也差不多。刚才又测了一次,换上了flash 10.1和sl4,结果大掉眼镜,sl成绩提高了1倍fl成绩下降了将近1倍。

  53. mcpssx
    113.57.9.*
    链接

    mcpssx 2010-07-04 12:54:38

    按下面这个例子测试连续累加,c++比as3快了30倍

    http://blog.csdn.net/fzhlee/archive/2010/04/25/5523931.aspx

    c++时间花了288,as3花了10202

  54. RednaxelaFX
    121.0.29.*
    链接

    RednaxelaFX 2010-07-06 13:16:59

    好久没来乱入一下了…

    或是在运行时回收JIT的代码(印象中在.NET Compact Framework里有这样的策略,求详情)

    .NET CF是有可配置的固定大小的code cache来保存JIT后的代码;满了之后就做code pitch(抛弃代码),把整个code cache清空然后重新JIT。SSCLI同样支持code pitching。

    這個概念其實像profile guided optimization,不過是動態進行。但兩者皆有共同缺點。它們都是估計將來的輸入數據特性相近,所以才可以透過統計方式提高期望的(expected)效能。但無論靜態或動態,都難以估計將來的輸入數據是否和profile的接近。動態的話,有可能可以進行適應性調整,但這種算法也不一定能帶來效能提升,反而會有profiling和JIT的開銷。

    三大JVM的JIT中的重要部分就是PGO。近年的一些研究就是试图找出更合适的profile模型和cost-benifit模型来估算优化哪部分代码、如何优化。动态优化的好处在支持动态加载的环境中会比较明显,因为这种环境中很可能无法静态完成whole program analysis,但却可以在运行时把当前状态当作“whole program”来分析并激进优化,而且仍然留下安全的退路。

    不算上pointer-to-member,C++的虚方法至少有两种方式调:通过实例调,或者是通过指针/引用调。例如说:

    A a;
    a.foo(); // 通过实例调
    A* p = &a;
    p->foo(); // 通过指针调
    

    即便foo()是虚方法,在a.foo()的形式下调用也必然是调到A的版本而不会是别的版本,因为可以安全的静态判定该实例一定是A类型的;而通过指针/引用调用则需要更多信息才可以安全的做静态单目标判定,这类才是“真”的方法调用。 顺带一提,C++也是有编译器对通过指针/引用调的虚方法的情况做激进优化的。可以参考篇96年的论文,作者正是参与了Sun的多个VM研发的人。

    CLR的GC老大Patrick Dussud说过托管运行时的一大好处是它可以较容易的保证类型安全。在需要动态分配空间的环境中,通过GC或其它自动内存管理方式来强制杜绝dangling pointer/double free之类的问题,禁止对内存的任意操作,是保证运行时类型安全的重要部分。 把经过高度tune过的不用GC的程序与普通的用GC的托管程序来比较性能是不合理的。GC是朋友而不是仆人,要用得高效一样需要tuning。

    虚拟机/运行时本身可以做的优化也很多,如果真觉得性能不够,那么完全可以在运行前在本地编译成native code,这和直接从源代码变成native code从结果上看没什么区别。但是现实是,很少有人去这么做,因为这么做往往只是节省了JIT的开销,对性能提高效果不大。

    现实是不少.NET程序有用NGEN的。至少.NET Framework自己用,微软写的不少用了.NET的程序也是安装时NGEN,以前我用的一个游戏脚本编辑器也是要求NGEN。对启动性能还是颇有影响的,对稳定性能则没什么实质好处,用普通NGEN预先编译的程序多半比运行时JIT的版本慢;当然这很大原因是NGEN实现得比较偷懒。

    那些“现在不快”的东西里很多都还有很多油水可榨。JavaScript引擎的演化是最好的例子,那些引擎们每隔几个月就能在SunSpider评测上把所需执行时间缩短一半是怎么可能的?与其说现在神乎其技,还是“以前太偷懒了”的说法更接近现实。IE9的JScript 9/Chakra引擎结构上其实跟client版HotSpot挺像的:混合模式的执行引擎中包含解释器与后台线程上工作的JIT编译器,JIT编译器也会做些现在看来很常规的优化,包括SSA形式的中间代码和相关常规优化、生成代码前的linear scan register allocation,之类的。跟以前纯解释器的JScript 5.6/5.7/5.8相比速度自然不可同日而语,就算是解释器本身JScript 9/Chakra也比以前的快多了。

    嗯顺带一提,纯解释器中快慢差异也可以很明显,在一些程序中Sun JDK 1.0系的解释器会比1.1系的解释器慢一倍。也不是JIT编译了就一定比纯解释快。首藤一幸提供过一组对比的例子,他最初写的简单JIT编译器的性能还比不上Sun JDK 1.1系列的解释器。LuaJIT的作者Mike Pall也表示LuaJIT 2里的解释器在一些场景里比LuaJIT 1的JIT编译后的代码还快。不要光看到某某VM有JIT编译器就以为它一定比纯解释器的方案快哦~☆

    说到JavaScript引擎,MSR最近宣传的SPUR项目值得关注。它的一个愿景就是用C#写一个浏览器,让SPUR能从JavaScript代码一直trace到JavaScript运行时内部,甚至到浏览器(DOM)一侧,极大的提高浏览器的整体性能。其中,CIL(或者说MSIL)作为一种便于分析的中间语言是实现这一愿景的重要组成部分(唔,虽然SPUR里用的不是“裸”的CIL而是改进过的、基于寄存器版的CIL,不过Herman Venter表示这个决定对性能的影响不大,只是因为有个研究员已经写了针对改进的CIL处理的程序,为了复用那些代码才把SPUR实现成这样的)。

    至于性能测试与结果的解读,这个就不提了。留给各位大牛们交流讨论把玩,呵呵。乱入结束。

  55. 路过
    183.37.78.*
    链接

    路过 2010-07-25 17:18:45

    是不是做了静态页??

  56. abc
    218.89.32.*
    链接

    abc 2010-09-18 12:28:24

    我只说理论,我的观点是虚拟机的效率未来必然会超过静态编译的效率。

    从理论上,通过JIT,托管代码比编译的本地代码性能可能会高很多。

    原因何在?在于输入上,所谓的优化,是有前提的,是对一定的输入集合进行优化的,比如一个函数f(x,y) = x+y 如果输入是自然数,那么x+y就要真正的执行加法,如果输入就一对,x=1,y=2,那么这个函数就被直接优化成3了,再也不会有运算。所以输入集合的减小,必然带来优化性能的提高。

    在编译代码的时候,我们假定的输入集合是S1,而同样的托管代码,虽然它的整体输入集合同样是S1,但是在某个时候,或者某个应用场合,或者某个用户那里,它的输入集合会是更小的一个集合S2,此时,托管代码会重新根据这个S2来进行重新编译,从而得到更高的效率。

  57. 火星大能猫
    222.92.17.*
    链接

    火星大能猫 2011-08-24 07:50:39

    飞信慢,那是因为winform的渲染效率的问题,如果用wpf开发,在win7下运行,绝对不慢.

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我