为什么C#比C++运行速度更快?
为什么C#比C++运行速度更快?
我没有开玩笑。
我有一个C#应用程序和一个C++应用程序。它们做着完全相同的事情,使用的代码量完全相同...
...而且C#的运行速度更快,不仅更快,而且是快了十倍。
这让我感到很奇怪,因为首先,我正在调试器中运行C#应用程序,这应该使C#变慢。其次,由于C#是使用.NET编译成MSIL二进制代码并具有许多额外特性的字节码,它应该变得更慢。而C ++只是纯粹的机器代码。
这是C#代码:
static void main() { ulong i = 0; while (i < 100000000000) { Console.WriteLine(i); i++; } }
而这是C++代码:
int main() { usigned long i = 0; while (i < 100000000000) { cout << i << endl; i++; } return 0; }
它们只是计算和显示一个数字。当C++的数字为1000时,C#的数字为7000(快了7倍)。
我甚至尝试编译它们两个,并使用命令提示符在没有调试器的情况下运行它们,命令为:cplusplus.exe && csharp.exe
是的,我知道这个问题可能会被认为是“离题”:P,或者可能是“不清楚在问什么”:/
但请,有人给我解释一下这个。
如果这很重要的话,我使用的CPU是Intel i7 2.5 Ghz。
编辑:
我尝试了cout << i << \"\\n\";的想法,以及std::ios_base::sync_with_stdio(false);的想法,但没有成功或结果的改变。
编辑2:我尝试了C语言的printf()函数,速度要快得多。比C#快3倍。
有人告诉我IO流非常慢,所以我尝试了它们两个都没有将结果写入控制台,而C++仍然比C#快得多。
总之,Writeline()比cout快得多,printf()比两者都快得多。因此,写入控制台是唯一会使其变慢的事情。
TLDR:printf()胜出,而控制台写操作会减慢速度。
我认为你对测试没有足够的谨慎。我按照下面的详细信息使用C++重建了你的测试,证明它要快得多:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CSScratch { class Program { static void Main(string[] args) { ulong i = 0; while (i < 1000000) { Console.WriteLine(i); i++; } } } }
我在VS2013 Release模式下构建了上述内容,生成了CSScratch.exe,并将其计时(在cygwin bash下)并重定向输出,以便不计算文件系统写入时间。结果非常一致,其中五次运行中最快的一次是:
time ./CSScratch.exe > NUL real 0m17.175s user 0m0.031s sys 0m0.124s
C++的等效内容:
#includeint main() { std::ios_base::sync_with_stdio(false); unsigned long i = 0; while (i < 1000000) { std::cout << i << '\n'; i++; } }
也通过VS2013编译:
cl /EHsc /O2 output.cc time ./output > NUL
其中五次运行中最慢的:
real 0m1.116s user 0m0.000s sys 0m0.109s
仍然比C#运行中最快的(17.175秒)更快(1.116秒)。
两个版本中的一些时间都花费在加载/动态链接、初始化等上。我修改了C++版本,将循环次数增加了10倍,但仍然只需要9.327秒——相当于C#在十分之一的工作量上所需的时间的一半。
(你可以通过设置更大的输出缓冲区来进一步调优C++版本,但通常不需要这样做)。
你的代码效率不高,因为:
- C++流对象默认与C的stdio同步,这使得它变慢。
- 你正在使用
endl
,这会进一步减慢速度。
修复这两个问题,你可以使用下面的代码:
int main() { std::ios_base::sync_with_stdio(false); usigned long i = 0; while (i < 100000000000) { cout << i << '\n'; //use \n, not endl i++; } return 0; }
编译时需要加上优化标志 (不管你用的是什么编译器,都必须这么做):
$ g++ main.cpp -O3 -o run.test $ time ./run.test
关于 sync_with_stdio(false)
和 endl
的解释,请参见我的答案:
希望这能帮到你。