c ++和c#速度比较

当你需要使用原始CPU功率时,我很担心C#处理繁重计算时的速度。

在计算方面,我一直认为C ++比C#快得多。 所以我做了一些快速测试。 第一个测试计算素数<整数n,第二个测试计算一些pandigital数字。 第二次测试的想法来自于: Pandigital Numbers

C#素数计算:

using System; using System.Diagnostics; class Program { static int primes(int n) { uint i, j; int countprimes = 0; for (i = 1; i <= n; i++) { bool isprime = true; for (j = 2; j <= Math.Sqrt(i); j++) if ((i % j) == 0) { isprime = false; break; } if (isprime) countprimes++; } return countprimes; } static void Main(string[] args) { int n = int.Parse(Console.ReadLine()); Stopwatch sw = new Stopwatch(); sw.Start(); int res = primes(n); sw.Stop(); Console.WriteLine("I found {0} prime numbers between 0 and {1} in {2} msecs.", res, n, sw.ElapsedMilliseconds); Console.ReadKey(); } } 

C ++变体:

 #include  #include  #include  int primes(unsigned long n) { unsigned long i, j; int countprimes = 0; for(i = 1; i <= n; i++) { int isprime = 1; for(j = 2; j >n; unsigned int start = clock(); res = primes(n); int tprime = clock() - start; cout<<"\nI found "<<res<<" prime numbers between 1 and "<<n<<" in "<<tprime<<" msecs."; return 0; } 

当我试图找到小于100,000的素数时,C#变体在0.409秒内完成,C ++变体在0.614秒内完成。 当我运行它们为1,000,000 C#时完成6.039秒而C ++运行时间约为12.987秒。

C#中的Pandigital测试:

 using System; using System.Diagnostics; class Program { static bool IsPandigital(int n) { int digits = 0; int count = 0; int tmp; for (; n > 0; n /= 10, ++count) { if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1))) return false; } return digits == (1 << count) - 1; } static void Main() { int pans = 0; Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 1; i <= 123456789; i++) { if (IsPandigital(i)) { pans++; } } sw.Stop(); Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds); Console.ReadKey(); } } 

C ++中的Pandigital测试:

 #include  #include  using namespace std; int IsPandigital(int n) { int digits = 0; int count = 0; int tmp; for (; n > 0; n /= 10, ++count) { if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1))) return 0; } return digits == (1 << count) - 1; } int main() { int pans = 0; unsigned int start = clock(); for (int i = 1; i <= 123456789; i++) { if (IsPandigital(i)) { pans++; } } int ptime = clock() - start; cout<<"\nPans:"<<pans<<" time:"<<ptime; return 0; } 

C#variant在29.906秒内运行,C ++在大约36.298秒内运行。

我没有触及任何编译器开关,并且C#和C ++程序都是使用调试选项编译的。 在我尝试运行测试之前,我担心C#会远远落后于C ++,但现在似乎C#的优势速度差异很大。

任何人都能解释一下吗? C#是jitted并且C ++是本机编译的,所以C ++比C#变体更快是正常的。

谢谢你的答案!

我已经为Release配置重新编写了所有测试。

第一次测试(素数)

C#(数字<100,0000):0.189秒C ++(数字<100,0000):0.036秒

C#(数字<1,000,000):5.300秒C ++(数字<1,000,000):1.166秒

第二次测试(pandigital数字):

C#:21.224秒C ++:4.104秒

所以,每一件事都发生了变化,现在C ++的速度要快得多。 我的错误是我已经运行了Debug配置的测试。 如果我通过ngen运行C#可执行文件,我能看到一些速度提升吗?

我试图比较C#和C ++的原因是因为我知道两者的一些基础知识,我想学习一个处理GUI的API。 我认为WPF很好,所以鉴于我的目标是桌面,我想看看C#在使用纯粹的CPU能力来计算各种计算(文件存档,加密,编解码器等)时是否能提供足够的速度和性能。 但遗憾的是,C#在速度方面无法与C ++保持同步。

所以,我假设我将永远坚持这个问题关于WPF,Win32,MFC的艰难问题 ,我会更新找到合适的API。

为什么你会认为jitted代码比本机代码慢? 唯一的速度惩罚是实际的点击,只发生一次(一般来说)。 鉴于一个运行时间为30秒的程序,我们讨论的是总成本的一小部分。

我认为你可能会将jitted代码与解释代码混淆,后者是逐行编译的。 这两者之间存在非常显着的差异。

正如其他人指出的那样,你还需要在发布模式下运行它; 调试模式会关闭大多数优化,因此两个版本都会比它们应该更慢(但是数量不同)。

编辑 – 我应该指出另一件事,就是这一行:

 for (j = 2; j <= Math.Sqrt(i); j++) 

是非常低效的,可能会干扰基准测试。 你应该在内循环之外计算Math.Sqrt(i) 。 这可能会使两个版本的速度减慢相等,但我不确定,不同的编译器会执行不同的优化。

您需要在发布模式下编译C ++并启用优化以获得您正在寻找的性能结果。

C ++中的素数生成器不正确

i ^(1/2)== i xor 0

^是按位xor运算符,/是整数除法。

第一次编辑 ,它是正确但无效的:因为我xor = = i,筛子不会停在sqrt(i)但是在i。

第二次编辑:

筛分可以更有效地完成。 (您只需要计算sqrt(n))。 这就是我为自己使用Eratosthenes筛子的方法(虽然这是在C99):

 void sieve(const int n, unsigned char* primes) { memset(primes, 1, (n+1) * sizeof(unsigned char)); // sieve of eratosthenes primes[0] = primes[1] = 0; int m = floor(sqrt(n)); for (int i = 2; i <= m; i++) if (primes[i]) // no need to remove multiples of i if it is not prime for (int j = i; j <= (n/i); j++) primes[i*j] = 0; } 

由于算法错误,所以需要更长的时间。

 for(j = 2; j < (i^(1/2)); j++) 

是相同的

 for(j = 2; j < (i^0); j++) 

是相同的

 for(j = 2; j < i; j++) 

我比sqrt(i)大很多。 看一下运行时间,它应该在C ++实现中大一个数量级。

此外,就像其他人都说的那样,我认为在调试模式下进行性能测试并不合理。

在打开完全优化的情况下重新编译C ++程序并重新运行测试。 C#jit将在jitted时优化代码,因此您将优化的C#/ .NET代码与未优化的C ++进行了比较。

首先,永远不要在调试模式下执行此类基准测试。 要获得有意义的数字,请始终使用发布模

JIT具有了解其运行的平台的优势,而预编译的代码对于运行的平台可能不是最理想的。

托管代码中的JIT编译器生成的机器代码效率远低于C / C ++编译器生成的机器代码,这是一个持久的神话。 托管代码通常在内存管理和浮点数学上获胜,当代码优化器可以花费更多时间优化代码时,C / C ++通常会获胜。 通常,托管代码约为80%,但它完全取决于程序花费90%时间的代码的10%。

您的测试不会显示此信息,您没有启用优化器,并且没有太多优化。

这两个测试都是无效的,因为您编译时没有进行优化。

由于代码中的错误,第一次测试即使是未优化行为的比较也毫无意义; Math.Sqrt(i)返回Math.Sqrt(i)的平方根, i^(1/2)返回i – 所以C ++比C#做了更多的工作。

更一般地说,这不是一件有用的事情 – 你正在尝试创建一个对现实世界使用几乎没有任何影响的综合基准测试。

伙计们,在比较程序速度之前,请仔细阅读有关cpu指令,汇编,缓存管理等的几篇文章。作者只是一个可笑的搞笑伙伴。 检查调试版本的性能。

比利奥尼尔 – 分配一个大缓冲区和只使用它的一小部分,并在低语言单词中使用动态分配的东西之间有什么区别? 一旦分配了大缓冲区 – 没有人会对未使用的东西感到烦恼。 无需进一步的支持操作。 而对于像vector这样的动态内容 – 对内存边界的不断检查不需要超出它。 请记住,C ++程序员不只是懒惰(我承认这是真的,但他们也很聪明)。

这个怎么样:

 for(sqrti = 1; sqrti <= 11112; sqrti++) { int nexti = (1+sqrti)*(1+sqrti) for (i = sqrti*sqrti; i < nexti; i++) { int isprime = 1; for(j = 2; j < sqrti; j++) if(!(i%j)) { isprime = 0; break; } } 

} countprimes + = isprime; }