我发现C anc C#中类似代码之间存在巨大的性能差异.
C代码是:
#include#include #include main() { int i; double root; clock_t start = clock(); for (i = 0 ; i <= 100000000; i++){ root = sqrt(i); } printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC); }
而C#(控制台应用程序)是:
using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { DateTime startTime = DateTime.Now; double root; for (int i = 0; i <= 100000000; i++) { root = Math.Sqrt(i); } TimeSpan runTime = DateTime.Now - startTime; Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds/1000)); } } }
使用上面的代码,C#在0.328125秒(发布版本)中完成,C运行需要11.14秒.
使用mingw将c编译为可执行的Windows.
我一直假设C/C++比C#.net更快或至少可以与C#.net相媲美.究竟是什么导致C运行速度慢了30多倍?
编辑:看起来C#优化器似乎正在删除root,因为它没有被使用.我将根分配更改为root + =并在结尾处打印出总计.我还使用cl.exe编译了C,其中/ O2标志设置为最大速度.
现在的结果是:C#2.61秒为3.75秒
C仍然需要更长的时间,但这是可以接受的
您必须比较调试版本.我只是编译了你的C代码,然后得到了
Time elapsed: 0.000000
如果您不启用优化,那么您所做的任何基准测试都是毫无价值的.(如果你确实启用了优化,那么循环就会被优化掉.所以你的基准测试代码也是有缺陷的.你需要强制它运行循环,通常是通过总结结果或类似结果,并在结束时打印出来)
您所测量的似乎基本上是"哪个编译器插入最多的调试开销".结果答案是C.但这并不能告诉我们哪个程序最快.因为当您想要速度时,您可以启用优化.
顺便说一下,如果你放弃任何语言比其他人"更快"的概念,你将从长远来看为自己省去很多麻烦.C#的速度不会超过英语.
即使在一个天真的非优化编译器中,C语言中的某些东西也会很有效,还有一些东西在很大程度上依赖于编译器来优化所有东西.当然,C#或任何其他语言也是如此.
执行速度由以下因素确定:
您正在运行的平台(操作系统,硬件,系统上运行的其他软件)
编译器
你的源代码
一个好的C#编译器将产生高效的代码.坏C编译器会生成慢代码.如何生成C#代码的C编译器,然后可以通过C#编译器运行?跑的速度有多快?语言没有速度.你的代码呢.
我会保持简短,它已经标记为已回答.C#具有定义良好的浮点模型的巨大优势.这恰好与x86和x64处理器上的FPU和SSE指令集的本机操作模式相匹配.那里没有巧合.JITter将Math.Sqrt()编译为一些内联指令.
本机C/C++背负着多年的向后兼容性./ fp:precise,/ fp:fast和/ fp:严格的编译选项是最明显的.因此,它必须调用实现sqrt()的CRT函数,并检查选定的浮点选项以调整结果.那很慢.
由于您从不使用"root",因此编译器可能已删除调用以优化您的方法.
您可以尝试将平方根值累积到累加器中,在方法结束时将其打印出来,然后查看正在发生的事情.
编辑:请参阅下面的Jalf的答案
我是C++和C#开发人员.自.NET框架的第一个测试版以来,我开发了C#应用程序,并且我在开发C++应用程序方面拥有超过20年的经验.首先,C#代码永远不会比C++应用程序更快,但我不会对托管代码,工作原理,操作间层,内存管理内部,动态类型系统和垃圾收集器进行冗长的讨论.不过,让我继续说,这里列出的基准都会产生不正确的结果.
让我解释一下:我们需要考虑的第一件事是C#(.NET Framework 4)的JIT编译器.现在,JIT使用各种优化算法(比Visual Studio附带的默认C++优化器更具攻击性)为CPU生成本机代码,.NET JIT编译器使用的指令集更接近实际CPU在机器上,可以在机器代码中进行某些替换,以减少时钟周期并提高CPU流水线高速缓存中的命中率,并产生进一步的超线程优化,例如指令重新排序和与分支预测相关的改进.
这意味着除非使用正确的RELEASE构建参数(而不是DEBUG构建)编译C++应用程序,否则C++应用程序的执行速度可能比相应的基于C#或.NET的应用程序慢.在C++应用程序上指定项目属性时,请确保启用"完全优化"和"支持快速代码".如果你有64位机器,你必须指定生成x64作为目标平台,否则你的代码将通过转换子层(WOW64)执行,这将大大降低性能.
在编译器中执行正确的优化后,C++应用程序获得0.72秒,C#应用程序获得1.16秒(两者都在发布版本中).由于C#应用程序非常基础并且在堆栈中而不是在堆上分配循环中使用的内存,因此它实际上比涉及对象,繁重计算和更大数据集的实际应用程序执行得更好.因此,提供的数据是偏向于C#和.NET框架的乐观数据.即使有这种偏见,C++应用程序的完成时间也只比同等的C#应用程序快一半.请记住,我使用的Microsoft C++编译器没有正确的管道和超线程优化(使用WinDBG查看汇编指令).
现在,如果我们使用英特尔编译器(顺便提一下,这是在AMD /英特尔处理器上生成高性能应用程序的行业秘密),相同的代码在.54秒内执行C++可执行文件,而使用Microsoft Visual Studio 2010执行.72秒最后,C++的最终结果为.54秒,C#为1.16秒.因此,.NET JIT编译器生成的代码比C++可执行文件长214%.在.54秒内花费的大部分时间是从系统中获取时间而不是在循环内部!
统计中还缺少的是启动和清理时间,这些时间未包含在时间中.与C++应用程序相比,C#应用程序在启动和终止上花费的时间更多.这背后的原因很复杂,并且与.NET运行时代码验证例程和内存管理子系统有关,后者在程序的开头(因此,结束时)执行大量工作以优化内存分配和垃圾集电极.
在测量C++和.NET IL的性能时,重要的是查看汇编代码以确保所有计算都存在.我发现,如果不在C#中添加一些额外的代码,上面示例中的大多数代码实际上都是从二进制文件中删除的.当您使用更积极的优化器(例如英特尔C++编译器附带的优化器)时,C++也是如此.我在上面提供的结果100%正确并在装配级别进行了验证.
互联网上很多论坛的主要问题是很多新手在没有理解技术的情况下听取微软的营销宣传,并且虚假声称C#比C++更快.声称理论上,C#比C++更快,因为JIT编译器可以优化CPU的代码.这个理论的问题在于,.NET框架中存在大量管道,这会降低性能; C++应用程序中不存在的管道.此外,经验丰富的开发人员将知道用于给定平台的正确编译器,并在编译应用程序时使用适当的标志.在Linux或开源平台上,这不是问题,因为您可以分发源并创建安装脚本,使用适当的优化来编译代码.在Windows或闭源平台上,您必须分发多个可执行文件,每个可执行文件都有特定的优化.将要部署的Windows可执行文件是基于(使用自定义操作)由MSI安装程序检测到CPU上.
我的第一个猜测是编译器优化,因为你从不使用root.你只需分配它,然后反复覆盖它.
编辑:该死的,击败了9秒!
要查看循环是否正在优化,请尝试将代码更改为
root += Math.Sqrt(i);
ans在C代码中类似,然后在循环外打印root的值.
也许c#编译器注意到你没有在任何地方使用root,所以它只是跳过整个for循环.:)
可能不是这种情况,但我怀疑原因是什么,它依赖于编译器实现.尝试使用Microsoft编译器(cl.exe,作为win32 sdk的一部分提供)使用优化和发布模式编译C程序.我打赌你会看到其他编译器的性能提升.
编辑:我不认为编译器可以只优化for循环,因为它必须知道Math.Sqrt()没有任何副作用.
无论什么时间差异.可能是,"经过的时间"无效.如果您能保证两个程序在完全相同的条件下运行,那么它只是一个有效的.
也许你应该尝试一场胜利.相当于$/usr/bin/time my_cprog;/usr/bin/time my_csprog
我把(根据你的代码)放在一起,在C和C#中进行了两次更具竞争力的测试.这两个使用模运算符编写一个较小的数组用于索引(它增加了一点开销,但是,嘿,我们试图比较性能[粗略级别]).
C代码:
#include#include #include #include void main() { int count = (int)1e8; int subcount = 1000; double* roots = (double*)malloc(sizeof(double) * subcount); clock_t start = clock(); for (int i = 0 ; i < count; i++) { roots[i % subcount] = sqrt((double)i); } clock_t end = clock(); double length = ((double)end - start) / CLOCKS_PER_SEC; printf("Time elapsed: %f\n", length); }
在C#中:
using System; namespace CsPerfTest { class Program { static void Main(string[] args) { int count = (int)1e8; int subcount = 1000; double[] roots = new double[subcount]; DateTime startTime = DateTime.Now; for (int i = 0; i < count; i++) { roots[i % subcount] = Math.Sqrt(i); } TimeSpan runTime = DateTime.Now - startTime; Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds / 1000)); } } }
这些测试将数据写入数组(因此不应允许.NET运行时剔除sqrt操作)尽管该数组明显更小(不想使用过多的内存).我在发布配置中编译了这些并在控制台窗口内运行它们(而不是从VS开始).
在我的计算机上,C#程序在6.2到6.9秒之间变化,而C版本在6.9和7.1之间变化.
如果您只是在程序集级别单步执行代码,包括单步执行平方根程序,您可能会得到问题的答案.
不需要受过教育的猜测.