我正在编写一个非常高性能的应用程序,每毫秒处理和处理数百个事件。
非托管C ++是否比托管c ++更快?为什么?
托管C ++处理CLR而不是OS和CLR负责内存管理,这简化了代码,并且可能比非托管C ++中“程序员”编写的代码更有效?还是有其他原因? 使用托管时,如果对程序员透明并由CLR处理,那么如何避免动态内存分配(这会导致性能损失)?
回到我的问题,托管C ++在速度方面是否比非托管C ++更有效?为什么?
答案 0 :(得分:8)
对此没有一个答案。作为一个真正的通用规则,本机代码通常会更快,但1)情况并非总是如此,2)有时差异太小而无法关注,以及3)代码写得多好通常会比管理与非管理产生更大的差异。
托管代码在虚拟机中运行。基本上,您从一个生成字节代码作为输出的编译器开始,然后将其提供给虚拟机。然后,虚拟机将其重新编译为机器代码并执行该代码。在某些情况下,这可以提供一些真正的优势。举一个例子,如果你有一个运行64位VM的64位处理器(差不多已经给定了)但是在64位处理器之前编写的旧程序很常见,VM仍然会将该字节代码编译为64-位机代码,它可以为至少一些代码提供相当大的速度优势。
同时,对于某些代码来说,它也可能是一个相当明显的缺点。特别是,编译器在用户等待时运行。为了适应这种情况,VM的编译器本身运行速度非常慢。虽然本机代码生成器有所不同,但是您选择的本机编译器至少包含一些在VM的字节码编译器中放弃的优化以保证其资源使用合理的可能性很大。
VM也使用垃圾收集器。垃圾收集器与手动管理内存具有相当不同的特性。对于许多手动管理器,分配内存相当昂贵。释放内存相当便宜,但与您发布的项目数量大致呈线性关系。其他手动管理人员大致反过来说,在释放内存时做额外的工作以便更快地进行分配。无论哪种方式,成本结构都不同于典型的收集器。
使用垃圾收集器,分配内存通常非常便宜。对于典型的(复制)收集器,释放内存的成本主要取决于已分配且仍然(至少可能)正在使用的对象的数量。
分配本身也有所不同。在本机C ++中,您通常在堆栈上创建大多数对象,其中分配和释放内存非常便宜。在托管代码中,您通常会动态分配更大百分比的内存,并在其中进行垃圾回收。
答案 1 :(得分:3)
您可以用任何语言编写慢速代码;相反,你可以使用体面的算法,这种算法几乎可以用于任何语言。
这里常见的答案是选择一种你已经知道的语言,使用适当的算法,然后对其进行分析以确定实际的热点。
我有点担心数百个事件每毫秒语句。这太可怕了。您是否合理地能够以任何语言进行预期的处理?
作为高性能系统上的C ++开发人员,我倾向于相信我能够分析和优化发出的代码。那说;有很高性能的.NET应用程序,编写器已经竭尽全力不在关键循环中进行动态内存分配 - 主要是通过使用预先创建的已分配的对象池。
所以重复我以前的评论:选择你已经知道的,然后调整。即使你走到了尽头;你可能会对你的问题空间有更多了解。
答案 2 :(得分:2)
这一切都取决于具体情况。
使非托管代码更快/托管代码更慢的事情:
使托管代码更快/非托管代码更慢的事情:
可能还有更多原因。
答案 3 :(得分:2)
托管代码在大多数情况下比非托管代码慢,即使.Net CLR在执行代码之前总是进行JIT编译(在程序运行时它没有多次编译但是它从不解释代码)
问题在于CLR做了很多检查,例如每当您尝试访问它时,查看是否在数组的边界上运行。这样可以减少缓冲区溢出等问题,但也会因为这些检查增加的开销而导致性能下降。
我已经看过C#优于C ++的实验,但这些实验是在代码中充分利用对象层次结构等进行的。当涉及数字运算时,你想要充分利用你的PC,你将不得不去使用非托管代码。
另外一点也已经提到了 - 当必须释放内存时,GC导致程序执行中有些不可预测的暂停。在非托管代码中进行内存管理时,您也需要这个时间,但是当您决定销毁一个对象时,它会更频繁地发生,这意味着它不会立即为整个程序完成,因此您不会有长时间的停顿。 / p>
答案 4 :(得分:0)
这里有很多好的答案,但是托管代码的一个方面可能是长期优势,它是运行时分析。由于托管编译器生成的代码是中间格式,因此可以根据实际使用情况优化实际执行的机器代码。如果大量使用特定的功能子集,JIT'er可以将机器代码本地化在同一个内存页面上,从而增加了局部性。如果从特定方法重复进行特定子调用,则JIT'er可以动态内联它。
这是对非托管代码的改进,其中内联必须提前“猜测”,并且过度内联是有害的,因为它会增加代码大小并导致导致(非常耗时)L2 / L1缓存未命中的位置问题。这些信息根本不适用于静态分析,因此只能在JIT环境中使用。运行时分析可以获得一系列可能的优势,例如优化的循环展开等。
我并不是说.NET JIT'er尽可能聪明,但我知道我已经听说过全局分析功能,我知道很多关于运行时分析的研究都是在Hewlett-Packard完成的和其他公司。
答案 5 :(得分:0)
答案 6 :(得分:-1)
首先,你的陈述“每毫秒处理数百个事件。”听起来很不切实际。除非您在计算机中有一个特殊设计的时钟模块,否则我不认为您可以通过通用PC实现目标(典型分辨率大约为10毫秒)。其次,Native C ++在性能方面要好得多。在C ++方面可以采取很多优化来加速,而在托管代码中它们是不可能的。还要注意托管代码中的垃圾收集会使性能无法预测 - 当GC启动时,整个过程会被冻结。一旦遇到问题,解决方案就会更加痛苦,现在托管代码提供的所有“好样式”都将消失。
至于管理代码可以针对CPU优化的能力,这是正确的,但您也可以利用本机C ++中的CPU功能(SSE2,MMX等)。根据我的经验,性能提升可以忽略不计。
答案 7 :(得分:-1)
按速度和电源顺序排列>> C> C ++> = C ++ / CLI> C#> =所有其他。但是在asm中创建Web服务是一个长期的痛苦。然后在正确的时间使用正确的语言进行正确的工作和正确的听众,以做到最好。
答案 8 :(得分:-2)
C ++ / CLI不是像Java一样的半解释语言吗?
另外,昨天没有人发表研究表明GC系统总是比非GC慢?