一起谈.NET技术,为什么我支持托管运行时(虚拟机)

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

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

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

  首先,统一运行时提供了跨平台的能力,Java便是一典型。.NET上有mono,使用也很广泛,也有不少Unity3D,Gnome DO等成功案例。Novell,包括其他一些公司也在销售基于mono的商业产品(如MonoTouch及Infragistics的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后的代码都可以回收再动态生成,这种优化是静态编译难以比拟的。

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

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

目录
相关文章
|
4天前
|
编解码 虚拟化 Windows
通过Hyper分辨率适配技术,可以解决虚拟机显示器上的分辨率适配难题
Hyper-V的增强会话模式通过RDP协议实现虚拟机与物理显示器的高质量连接,支持更高分辨率、优化图形性能,并提供共享剪贴板、拖放文件等增强功能。启用此模式可解决虚拟机分辨率适配难题,提升显示效果和交互性。需确保操作系统支持RDP,网络稳定,且注意对主机性能的影响。
|
6天前
|
编解码 监控 虚拟化
Hyper分辨率优化技术,怎么使得虚拟机中的图形应用能够以更高的清晰度呈现
Hyper分辨率优化技术通过增强虚拟机的图形处理能力,显著提升图像清晰度和视觉体验,适用于图形设计、视频编辑等场景。该技术依赖于虚拟机的硬件配置、显卡驱动及显示设置,确保高分辨率内容的最佳呈现。使用时需合理设置分辨率,定期更新驱动并监控性能,以实现最佳效果。
|
3月前
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
|
3月前
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
|
4月前
|
前端开发 Android开发
WinForm 直接运行 Admin.NET
本文介绍了如何将 Admin.NET 以 WinForm 桌面程序模式运行,简化了手动配置 Web 服务的过程,便于演示和作为单机软件使用。通过添加特定 NuGet 包、修改 `Program.cs` 和 `Form1.cs` 文件,并调整项目配置,最终实现了在 WinForm 中嵌入 WebView 组件显示 Admin.NET 界面的效果。
47 0
WinForm 直接运行 Admin.NET
|
4月前
|
机器学习/深度学习 人工智能 Cloud Native
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台。本文深入解析 .NET 的核心优势,探讨其在企业级应用、Web 开发及移动应用等领域的应用案例,并展望未来在人工智能、云原生等方面的发展趋势。
65 3
|
4月前
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
57 3
|
4月前
|
开发框架 安全 Java
.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力
本文深入探讨了.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力。.NET不仅支持跨平台开发,具备出色的安全性和稳定性,还能与多种技术无缝集成,为企业级应用提供全面支持。
96 3
|
4月前
|
传感器 人工智能 供应链
.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。
本文深入探讨了.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。通过企业级应用、Web应用及移动应用的创新案例,展示了.NET在各领域的广泛应用和巨大潜力。展望未来,.NET将与新兴技术深度融合,拓展跨平台开发,推动云原生应用发展,持续创新。
62 4

热门文章

最新文章