我想在C和C#之间做一个小的基准测试,所以我编写了以下程序:
C:
int main()
{
int i = 1;
while (i <= 500000)
{
printf("%d", i);
i++;
}
}
C#:
class Program
{
static void Main(string[] args)
{
int i = 1;
while (i <= 500000)
{
Console.Write(i);
i++;
}
}
}
然后我编译它们并同时运行它们。
令我惊讶的是,C#程序比C程序提前了大约5秒。
C是一种以其高速和高性能而闻名的语言,那么在这种情况下,C#程序如何在这么简单的任务中显着优于C程序呢?我认为C#速度慢得多,因为它在运行时编译,但它很容易击败从C编译的本机可执行文件。
这是什么原因,在其他类型的程序中是否也会发生这种情况?
我在Windows 8.1 Pro 64位上运行这两个程序,如果这很重要,并在C#Express 2010中编译C#程序,在VS2013 Express for Desktop中编译C程序。
请不要打击我这么常见的问题&#34; - 是的,我已经看到了另一个答案,但他们都处理了复杂的事情例如内存管理和缓冲区大小,这里的程序非常简单,不处理那些事情。
我还尝试将printf
替换为puts
,但这也很慢。
答案 0 :(得分:10)
对编程语言写入控制台的速度进行基准测试毫无价值。这是这两种情况的瓶颈,而且它会搞砸你的结果。其中一个程序(C或C#版本)的执行时间从一次运行到下一次运行会有很大差异。因此,两种语言之间的任何比较都是毫无意义的。
如果确实想要测试性能差异,那么一种方法就是编写复杂的数学算法并对其进行基准测试。不要把结果写到控制台,但是你现在知道这会破坏目的!此外,请使用高分辨率计时器。在C#中,您将使用Stopwatch
class;在C(至少在Windows上),你打电话给QueryPerformanceCounter
function。 a real stopwatch的时间安排太容易出错。或者至少它适合我。无论哪种方式,请确保您在正在测试的代码中查询 之外的值。
答案 1 :(得分:7)
这与C语言或其编译器没有任何关系,与其运行时支持库有关。减速是由您使用printf()。
引起的C运行时库(CRT)严重陷入泥潭,为可追溯到20世纪70年代的运行时环境建模。回到程序员使用电传打字机与计算机交谈的时候,有一个非常原始的操作系统,它不支持线程,用英语交谈等好东西。
运行时环境与现代操作系统非常不匹配,需要相当大的开销来模拟它。例如,C语言对Unicode的支持非常差。因此,您输出的每个字符串都必须精心转换为本机操作系统的字符串格式,即Windows中的utf-16。 .NET Framework使用System.String,这是一种在utf-16中编码的字符串类型。即使是最低级别,Windows也要求字符串为零终止,就像C字符串需要的那样。每个.NET字符串都会自动为零终止,即使是那些您不能用于I / O的字符串。因此不需要转换,框架可以直接调用输出字符串的操作系统函数。
那不是它结束的地方。线程的概念与CRT完全不同,它从未被设计为考虑多线程的分支,例如,修改语言环境或同时编写文本。所以CRT充满了低级锁定,以实现这一目标。实际上很少有用的开销,但必须采用,因为20世纪70年代的运行时模型不允许或不考虑它。
你可以使你的C程序与你的C#程序一样快,使得显着更快有点延伸,但你必须绕过20世纪70年代这样做。使用wprintf()代替已经应该有明显的区别,在调用WriteConsoleW()或WriteFile()之前,你不会得到奇偶校验。
请注意,这实际上并不重要。无论如何,文本在屏幕上滚动的速度远远快于人类可以读取的速度。因此,任何人都不会考虑修复这个问题。