C ++性能与Java / C#

我的理解是C / C ++生成本地代码以在特定的机器体系结构上运行。 相反,像Java和C#这样的语言运行在虚拟机的顶部,虚拟机抽象出本地体系结构。 从逻辑上讲,Java或C#似乎不可能匹配C ++的速度,因为这个中间步骤,然而我被告知最新的编译器(“热点”)可以达到这个速度甚至超过它。

也许这更像是一个编译问题,而不是一个语言问题,但任何人都可以用简单的英语解释这些虚拟机语言之一是否可能比本地语言执行得更好?


一般来说,C#和Java可以同样快或更快,因为JIT编译器(一种在首次执行时编译IL的编译器)可以优化C ++编译程序无法执行的优化,因为它可以查询计算机。 它可以确定机器是Intel还是AMD; Pentium 4,Core Solo或Core Duo; 或者如果支持SSE4等

一个C ++程序必须事先通过混合优化进行编译,这样它才能在所有机器上运行得很好,但没有像单个配置(即处理器,指令集和其他硬件)那样优化。

此外,某些语言特性允许C#和Java中的编译器对您的代码进行假设,使其能够优化某些部分,而这些部分对于C / C ++编译器来说是不安全的。 当你有权访问指针时,有很多优化是不安全的。

此外,Java和C#可以比C ++更有效地进行堆分配,因为垃圾收集器和代码之间的抽象层允许它一次完成所有的堆压缩(相当昂贵的操作)。

现在我无法在下一点上谈论Java,但是我知道C#例如在知道方法的主体为空时实际上将删除方法和方法调用。 它将在整个代码中使用这种逻辑。

正如你所看到的,为什么某些C#或Java实现会更快,有很多原因。

现在这一切都表示,可以用C ++进行特定的优化,这将会吹走你可以用C#做​​的任何事情,特别是在图形领域以及任何你接近硬件的时候。 指针在这里创造奇迹。

所以根据你写的内容,我会选择其中一个。 但是如果你写的东西不是依赖硬件的(驱动程序,视频游戏等),我不会担心C#的性能(再也不会谈论Java)。 它会做得很好。

一个Java方面,@Swati指出了一篇好文章:

https://www.ibm.com/developerworks/library/j-jtp09275


JIT与静态编译器

正如前面的文章所述,JIT可以在运行时将IL /字节码编译为本地代码。 提到的成本,但没有得出结论:

JIT有一个巨大的问题是它无法编译所有的东西:JIT编译需要时间,因此JIT将仅编译代码的一部分,而静态编译器将生成完整的本机二进制文件:对于某些类型的程序,静态编译器将简单地胜过JIT。

当然,与C ++相比,C#(或者Java或VB)通常可以更快地生成可行且健壮的解决方案(如果仅仅因为C ++具有复杂的语义,并且C ++标准库虽然有趣且强大,但与完整来自.NET或Java的标准库的范围),所以通常,C ++和.NET或Java JIT之间的区别对于大多数用户来说是不可见的,对于那些关键的二进制文件,您仍然可以调用C ++处理来自C#或Java(即使这种本地调用本身可能相当昂贵)...

C ++元编程

请注意,通常,您将C ++运行时代码与其在C#或Java中的等效代码进行比较。 但是C ++有一个功能可以超越Java / C#开箱即用,即模板元编程:代码处理将在编译时完成(因此会增加编译时间),导致运行时为零(或几乎为零)。

我还没有看到真实的生活效果(我只玩概念,但到那时为止,差异是JIT的执行时间,C ++ 为零 ),但这是值得一提的,除了事实模板元编程不是不重要的...

编辑2011-06-10:在C ++中,玩类型是在编译时完成的,意思是生成调用非泛型代码的泛型代码(例如,从字符串到T类型的通用解析器,为它识别的类型调用标准库API,并使得解析器易于被用户扩展)非常简单且非常高效,而Java或C#中的等价物在写入时是痛苦的,并且即使在编译时已知类型,运行时也会更慢并且解决,这意味着你唯一的希望就是让JIT把整个事情联系起来。

...

编辑2011-09-20:Blitz ++(主页,维基百科)背后的团队走的是这样,显然,他们的目标是通过C ++模板元编程尽可能地从运行时执行到编译时间,以达到FORTRAN在科学计算上的表现。 因此,我在上面写的“我已经看到了真实的生活效果”这个部分显然确实存在于现实生活中。

本机C ++内存使用情况

C ++具有与Java / C#不同的内存使用情况,因此具有不同的优点/缺陷。

无论JIT优化如何,都不会有像指向内存的直接访问(让我们暂时忽略处理器缓存等)。 所以,如果你在内存中有连续的数据,通过C ++指针(即C指针......让Caesar到期)访问它将比Java / C#中的时间快。 而且C ++有RAII,这使得大量的处理比C#或甚至Java更容易。 C ++不需要using来限定其对象的存在。 而C ++没有finally子句。 这不是一个错误。

:-)

尽管C#原始类结构,C ++“堆栈”对象将不会在分配和销毁时花费任何代价,并且不需要GC在独立线程中进行清理。

至于内存碎片,2008年的内存分配器不是从1980年开始的旧的内存分配器,通常与GC相比:C ++分配无法在内存中移动,不过,就像在Linux文件系统上一样:谁需要硬盘碎片没有发生时进行碎片整理? 使用正确的分配器进行正确的任务应该是C ++开发人员工具包的一部分。 现在,编写分配器并不容易,然后,我们大多数人都有更好的事情要做,对于大多数使用,RAII或GC都不够好。

编辑2011-10-04:有关高效分配器的示例:在Windows平台上,自Vista以来,低碎片堆默认情况下处于启用状态。 对于以前的版本,可以通过调用WinAPI函数HeapSetInformation来激活LFH)。 在其他操作系统上,提供了替代分配器(请参阅https://secure.wikimedia.org/wikipedia/en/wiki/Malloc获取列表)

现在,随着多核和多线程技术的兴起,内存模型变得越来越复杂。 在这个领域,我认为.NET有优势,据我所知,Java占据了上风。 一些“裸机”黑客很容易称赞他的“机器附近”代码。 但是现在,要让编译器工作起来,手工生成更好的汇编就相当困难。 对于C ++来说,自十年以来,编译器通常比黑客更好。 对于C#和Java,这更容易。

尽管如此,新的标准C ++ 0x将为C ++编译器强加一个简单的内存模型,这将在C ++中标准化(并因此简化)有效的多处理/并行/线程代码,并为编译器提供更简单,更安全的优化。 但是,接下来几年我们会看到它的承诺是否成立。

C ++ / CLI与C#/ VB.NET

注意:在本节中,我正在讨论C ++ / CLI,即.NET托管的C ++,而不是本机C ++。

上周,我对.NET优化进行了培训,发现静态编译器无论如何都非常重要。 和JIT一样重要。

在C ++ / CLI(或其祖先,Managed C ++)中编译的相同代码可能比在C#中生成的代码(或VB.NET,其编译器生成的C#相同的IL)快得多。

因为C ++静态编译器比C#更好地生成已优化的代码。

例如,.NET中的函数内联仅限于字节码长度小于或等于32字节的函数。 因此,C#中的一些代码将生成一个40字节的访问器,JIT不会内联这些访问器。 C ++ / CLI中的相同代码将生成一个20字节的访问器,它将由JIT内联。

另一个例子是临时变量,它们被C ++编译器简单地编译掉,而在C#编译器生成的IL中仍然提到。 C ++静态编译优化将导致更少的代码,从而再次授权更积极的JIT优化。

原因被推测为C ++ / CLI编译器从C ++本地编译器的大量优化技术中获益的事实。

结论

我喜欢C ++。

但就我所见,C#或Java都是更好的选择。 并不是因为它们比C ++更快,而是因为当你将它们的特质加起来时,它们最终会变得更加高效,需要更少的培训,并且拥有比C ++更完整的标准库。 而对于大多数程序来说,它们的速度差异(以这种或那种方式)将可以忽略不计......

编辑(2011-06-06)

我在C#/ .NET上的经验

我现在已经有5个月的几乎专业的C#编程(这加起来就是我的CV已经充满了C ++和Java,还有一些C ++ / CLI)。

我使用WinForms(Ahem ...)和WCF(cool!),以及WPF(Cool !!!!都通过XAML和原始C#,WPF非常简单,我相信Swing无法与之比较)和C#4.0。

结论是,尽管生成一个在C#/ Java中工作的代码比在C ++中更容易/更快,但在C#中生成强大,安全和健壮的代码(甚至在Java中更难)比C ++更难。 原因比比皆是,但可以总结为:

  • 泛型不如模板强大(尝试编写一个高效的通用Parse方法(从字符串到T),或者在C#中使用一个高效的boost :: lexical_cast类来理解问题)
  • RAII仍然无法匹敌(GC仍然可能会泄漏(是的,我必须处理这个问题),并且只能处理内存。即使C#的using也不是那么容易和强大,因为编写正确的Dispose实现很困难)
  • C# readonly和Java final与C ++的const没有任何const (你无法在C#中使用C#展现只读复杂数据(例如Tree of Nodes),而无需大量工作,而它是C ++的一个内置功能。一个有趣的解决方案,但并非所有东西都可以做到不变,所以它远远不够)。
  • 所以,只要你想要一些可行的东西,C#仍然是一种令人愉快的语言,但是当你想要一些总是安全地工作的时候,C#就是令人沮丧的语言。

    Java更令人沮丧,因为它具有与C#相同的问题,还有更多: using关键字缺少相当于C#的using ,我的一位非常熟练的同事花费了太多时间来确保其资源在正确释放的位置,而C ++中的等价物会很容易(使用析构函数和智能指针)。

    所以我想大多数代码都可以看到C#/ Java的生产力增加......直到你需要代码尽可能完美为止。 那一天,你会知道痛苦。 (你不会相信我们的服务器和GUI应用程序要求什么...)。

    关于服务器端Java和C ++

    我一直与服务器团队保持联系(我在其中工作了两年,然后回到GUI团队),在大楼的另一侧,我学到了一些有趣的东西。

    去年,趋势是让Java服务器应用程序注定要替换旧的C ++服务器应用程序,因为Java有很多框架/工具,并且易于维护,部署等。

    ......直到低延迟问题在最后几个月才出现丑陋的头脑。 然后,Java服务器应用程序,不管我们熟练的Java团队尝试的优化如何,都简单而干净地失去了与旧的,并非真正优化的C ++服务器的竞争。

    目前,决定是保持Java服务器的通用性,而性能仍然很重要,不受低延迟目标的影响,并积极优化已经更快的C ++服务器应用程序,以满足低延迟和超低延迟需求。

    结论

    没有什么比预期的简单。

    Java甚至更多的C#都是很酷的语言,它有大量的标准库和框架,您可以在其中快速编写代码,并且很快就会有结果。

    但是,当您需要原始动力,强大而系统的优化,强大的编译器支持,强大的语言功能以及绝对安全的功能时,Java和C#使您很难赢得最后缺失但关键的质量百分比,以保持高于竞争对手的水平。

    就好像您在C#/ Java中需要的时间和经验较少的开发人员比在C ++中生成平均质量代码所需的时间更少,但另一方面,当您需要优秀的代码来完善优质代码时,获得结果突然变得更容易和更快在C ++中是正确的。

    当然,这是我自己的看法,可能仅限于我们的具体需求。

    但是,现在发生在GUI团队和服务器端团队中的情况都是如此。

    当然,如果有新事发生,我会更新这篇文章。

    编辑(2011-06-22)

    “我们发现,在性能方面,C ++大幅度胜出,但它也需要最广泛的调整工作,其中许多工作都是在一般程序员无法获得的复杂程度上完成的。

    [...] Java版本可能是最简单的实现,但最难分析性能。 具体来说,垃圾回收的影响很复杂,很难调整。“

    资料来源:

  • https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
  • http://www.computing.co.uk/ctg/news/2076322/-winner-google-language-tests
  • 编辑(2011-09-20)

    “在Facebook上发表的言论是”合理编写的C ++代码运行速度很快“,这强调了在优化PHP和Java代码方面花费的大量精力。矛盾的是,C ++代码比其他语言编写起来更困难,但高效的代码是很容易[用C ++编写而不是其他语言]。“

    - Herb Sutter在// build /引用Andrei Alexandrescu

    资料来源:

  • http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T
  • http://video.ch9.ms/build/2011/slides/TOOL-835T_Sutter.pptx

  • 每当我谈论托管和非托管性能时,我都喜欢指出Rico(和Raymond)系列确实比较了C ++和C#版本的中文/英文字典。 这谷歌搜索将让你自己阅读,但我喜欢里科的总结。

    所以我为自己惨败而感到羞耻? 几乎不。 几乎没有任何努力,托管代码获得了非常好的结果。 打败管理的雷蒙德不得不:

  • 写他自己的文件I / O的东西
  • 写他自己的字符串类
  • 写他自己的分配器
  • 写他自己的国际映射
  • 当然,他使用可用的低级库来做到这一点,但这仍然是很多工作。 你可以调用什么是STL程序? 我不这么认为,我认为他保留了std :: vector类,它最终从来都不是问题,他保留了find函数。 几乎一切都消失了。

    所以,你可以肯定地击败CLR。 雷蒙德可以让他的节目更快,我想。

    有趣的是,两个程序内部定时器报告的解析文件的时间大致相同 - 每个30ms。 不同之处在于开销。

    对我来说,底线是非托管版本需要6次修订才能击败原始非托管代码的简单端口的托管版本。 如果你需要每一分钟的表现(并且有足够的时间和专业知识来获得它),你将不得不不受管理,但是对于我来说,我将在第一版的33如果我尝试6次,我会获益。

    链接地址: http://www.djcxy.com/p/85403.html

    上一篇: C++ performance vs. Java/C#

    下一篇: Why do compilations take so long?