C# vs C - 巨大的性能差异
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/686483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# vs C - Big performance difference
提问by John
I'm finding massive performance differences between similar code in C anc C#.
我发现 C 和 C# 中的类似代码之间存在巨大的性能差异。
The C code is:
C代码是:
#include <stdio.h>
#include <time.h>
#include <math.h>
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);
}
And the C# (console app) is:
而 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));
}
}
}
With the above code, the C# completes in 0.328125 seconds (release version) and the C takes 11.14 seconds to run.
使用上面的代码,C# 在 0.328125 秒内完成(发布版本),而 C 需要 11.14 秒来运行。
The c is being compiled to a windows executable using mingw.
正在使用 mingw 将 c 编译为 Windows 可执行文件。
I've always been under the assumption that C/C++ were faster or at least comparable to C#.net. What exactly is causing the C to run over 30 times slower?
我一直假设 C/C++ 更快或至少与 C#.net 相当。究竟是什么导致 C 运行速度慢了 30 倍?
EDIT: It does appear that the C# optimizer was removing the root as it wasn't being used. I changed the root assignment to root += and printed out the total at the end. I've also compiled the C using cl.exe with the /O2 flag set for max speed.
编辑:看起来 C# 优化器正在删除根,因为它没有被使用。我将根分配更改为 root += 并在最后打印出总数。我还使用 cl.exe 编译了 C,并为最大速度设置了 /O2 标志。
The results are now: 3.75 seconds for the C 2.61 seconds for the C#
现在的结果是: C 为 3.75 秒 C# 为 2.61 秒
The C is still taking longer, but this is acceptable
C 仍然需要更长的时间,但这是可以接受的
采纳答案by Brann
Since you never use 'root', the compiler may have been removing the call to optimize your method.
由于您从不使用“root”,编译器可能已经删除了优化您的方法的调用。
You could try to accumulate the square root values into an accumulator, print it out at the end of the method, and see what's going on.
您可以尝试将平方根值累加到累加器中,在方法结束时将其打印出来,然后看看发生了什么。
Edit : see Jalf's answerbelow
编辑:请参阅下面的Jalf 回答
回答by Neil N
my first guess is a compiler optimization because you never use root. You just assign it, then overwrite it again and again.
我的第一个猜测是编译器优化,因为您从不使用 root。您只需分配它,然后一次又一次地覆盖它。
Edit: damn, beat by 9 seconds!
编辑:该死的,被击败了 9 秒!
回答by i_am_jorf
Maybe the c# compiler is noticing you don't use root anywhere, so it just skips the whole for loop. :)
也许 c# 编译器注意到你没有在任何地方使用 root,所以它只是跳过整个 for 循环。:)
That may not be the case, but I suspect whatever the cause is, it is compiler implementation dependent. Try compiling you C program with the Microsoft compiler (cl.exe, available as part of the win32 sdk) with optimizations and Release mode. I bet you'll see a perf improvement over the other compiler.
情况可能并非如此,但我怀疑无论原因是什么,它都取决于编译器实现。尝试使用带有优化和发布模式的 Microsoft 编译器(cl.exe,作为 win32 sdk 的一部分提供)编译您的 C 程序。我敢打赌,您会看到性能比其他编译器有所改进。
EDIT: I don't think the compiler can just optimize out the for loop, because it would have to know that Math.Sqrt() doesn't have any side-effects.
编辑:我不认为编译器可以优化 for 循环,因为它必须知道 Math.Sqrt() 没有任何副作用。
回答by Hyman Ryan
It would seem to me that this is nothing to do with the languages themselves, rather it is to do with the different implementations of the square root function.
在我看来,这与语言本身无关,而是与平方根函数的不同实现有关。
回答by David M
The other factor that may be an issue here is that the C compiler compiles to generic native code for the processor family you target, whereas the MSIL generated when you compiled the C# code is then JIT compiled to target the exact processor you have complete with any optimisations that may be possible. So the native code generated from the C# may be considerably faster than the C.
这里可能有问题的另一个因素是,C 编译器编译为您所针对的处理器系列的通用本机代码,而编译 C# 代码时生成的 MSIL 然后被 JIT 编译为针对您已完成的任何处理器可能的优化。因此,从 C# 生成的本机代码可能比 C 快得多。
回答by David M
To see if the loop is being optimised away, try changing your code to
要查看循环是否被优化掉,请尝试将代码更改为
root += Math.Sqrt(i);
ans similarly in the C code, and then print the value of root outside the loop.
在 C 代码中也类似,然后在循环外打印 root 的值。
回答by Dana
Actually guys, the loop is NOT being optimized away. I compiled John's code and examined the resulting .exe. The guts of the loop are as follows:
实际上,循环并没有被优化掉。我编译了 John 的代码并检查了生成的 .exe。循环的内容如下:
IL_0005: stloc.0
IL_0006: ldc.i4.0
IL_0007: stloc.1
IL_0008: br.s IL_0016
IL_000a: ldloc.1
IL_000b: conv.r8
IL_000c: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_0011: pop
IL_0012: ldloc.1
IL_0013: ldc.i4.1
IL_0014: add
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: ldc.i4 0x5f5e100
IL_001c: ble.s IL_000a
Unless the runtime is smart enough to realize the loop does nothing and skips it?
除非运行时足够聪明以实现循环什么都不做并跳过它?
Edit: Changing the C# to be:
编辑:将 C# 更改为:
static void Main(string[] args)
{
DateTime startTime = DateTime.Now;
double root = 0.0;
for (int i = 0; i <= 100000000; i++)
{
root += Math.Sqrt(i);
}
System.Console.WriteLine(root);
TimeSpan runTime = DateTime.Now - startTime;
Console.WriteLine("Time elapsed: " +
Convert.ToString(runTime.TotalMilliseconds / 1000));
}
Results in the time elapsed (on my machine) going from 0.047 to 2.17. But is that just the overhead of adding a 100 million addition operators?
结果经过的时间(在我的机器上)从 0.047 到 2.17。但这仅仅是添加 1 亿个加法运算符的开销吗?
回答by jalf
You must be comparing debug builds. I just compiled your C code, and got
您必须比较调试版本。我刚刚编译了你的 C 代码,并得到了
Time elapsed: 0.000000
If you don't enable optimizations, any benchmarking you do is completely worthless. (And if you do enable optimizations, the loop gets optimized away. So your benchmarking code is flawed too. You need to force it to run the loop, usually by summing up the result or similar, and printing it out at the end)
如果您不启用优化,则您所做的任何基准测试都毫无价值。(如果你启用了优化,循环就会被优化掉。所以你的基准测试代码也有缺陷。你需要强制它运行循环,通常是总结结果或类似的,并在最后打印出来)
It seems that what you're measuring is basically "which compiler inserts the most debugging overhead". And turns out the answer is C. But that doesn't tell us which program is fastest. Because when you want speed, you enable optimizations.
似乎您正在测量的基本上是“哪个编译器插入的调试开销最多”。事实证明答案是 C。但这并不能告诉我们哪个程序最快。因为当您想要速度时,您可以启用优化。
By the way, you'll save yourself a lot of headaches in the long run if you abandon any notion of languages being "faster" than each others. C# no more has a speed than English does.
顺便说一句,如果您放弃任何语言比其他语言“更快”的概念,从长远来看,您将为自己省去很多麻烦。C# 的速度并不比英语快。
There are certain things in the C language that would be efficient even in a naive non-optimizing compiler, and there are others that relies heavily on a compiler to optimize everything away. And of course, the same goes for C# or any other language.
C 语言中的某些东西即使在幼稚的非优化编译器中也是有效的,还有其他东西严重依赖编译器来优化所有东西。当然,C# 或任何其他语言也是如此。
The execution speed is determined by:
执行速度由以下因素决定:
- the platform you're running on (OS, hardware, other software running on the system)
- the compiler
- your source code
- 您正在运行的平台(操作系统、硬件、系统上运行的其他软件)
- 编译器
- 你的源代码
A good C# compiler will yield efficient code. A bad C compiler will generate slow code. What about a C compiler which generated C# code, which you could then run through a C# compiler? How fast would that run? Languages don't have a speed. Your code does.
一个好的 C# 编译器将产生高效的代码。糟糕的 C 编译器会生成缓慢的代码。生成 C# 代码的 C 编译器怎么样,然后您可以通过 C# 编译器运行这些代码?那会跑多快?语言没有速度。你的代码可以。
回答by Tom
Whatever the time diff. may be, that "elapsed time" is invalid. It would only be a valid one if you can guarantee that both programs run under the exact same conditions.
无论时差如何。可能是,那个“经过的时间”是无效的。如果您能保证两个程序在完全相同的条件下运行,它才是有效的。
Maybe you should try a win. equivalent to $/usr/bin/time my_cprog;/usr/bin/time my_csprog
也许你应该尝试获胜。相当于 $/usr/bin/time my_cprog;/usr/bin/time my_csprog
回答by Cecil Has a Name
I put together (based on your code) two more comparable tests in C and C#. These two write a smaller array using the modulus operator for indexing (it adds a little overhead, but hey, we're trying to compare performance [at a crude level]).
我在 C 和 C# 中(根据您的代码)将两个更具可比性的测试放在一起。这两个使用模数运算符编写一个较小的数组进行索引(它增加了一点开销,但是嘿,我们正在尝试比较性能 [在粗略的级别])。
C code:
代码:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
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);
}
In C#:
在 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));
}
}
}
These tests write data to an array (so the .NET runtime shouldn't be allowed to cull the sqrt op) although the array is significantly smaller (didn't want to use excessive memory). I compiled these in release config and run them from inside a console window (instead of starting through VS).
这些测试将数据写入数组(因此不应允许 .NET 运行时剔除 sqrt 操作),尽管数组要小得多(不想使用过多的内存)。我在发布配置中编译了这些并从控制台窗口中运行它们(而不是通过 VS 启动)。
On my computer the C# program varies between 6.2 and 6.9 seconds, while the C version varies between 6.9 and 7.1.
在我的电脑上,C# 程序在 6.2 到 6.9 秒之间变化,而 C 版本在 6.9 和 7.1 之间变化。