的Delphi:
procedure TForm1.Button1Click(Sender: TObject);
var I,Tick:Integer;
begin
Tick := GetTickCount();
for I := 0 to 1000000000 do
begin
end;
Button1.Caption := IntToStr(GetTickCount()-Tick)+' ms';
end;
C#:
private void button1_Click(object sender, EventArgs e)
{
int tick = System.Environment.TickCount;
for (int i = 0; i < 1000000000; ++i)
{
}
tick = System.Environment.TickCount - tick;
button1.Text = tick.ToString()+" ms";
}
Delphi提供大约515毫秒
C#给出大约3775毫秒
答案 0 :(得分:28)
Delphi被编译为本机代码,而C#被编译为CLR代码,然后在运行时进行翻译。那就是说C#确实使用了JIT编译,所以你可能期望时间更相似,但它不是给定的。
如果你能描述你运行它的硬件(CPU,时钟频率),那将会很有用。
我无法访问Delphi重复您的实验,但使用原生C ++与C#以及以下代码:
VC ++ 2008
#include <iostream>
#include <windows.h>
int main(void)
{
int tick = GetTickCount() ;
for (int i = 0; i < 1000000000; ++i)
{
}
tick = GetTickCount() - tick;
std::cout << tick << " ms" << std::endl ;
}
<强> C#强>
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int tick = System.Environment.TickCount;
for (int i = 0; i < 1000000000; ++i)
{
}
tick = System.Environment.TickCount - tick;
Console.Write( tick.ToString() + " ms" ) ;
}
}
}
我最初得到了:
C++ 2792ms
C# 2980ms
然而,我在C#版本上执行了Rebuild,并分别直接从命令行运行<project>\bin\release
和<project>\bin\debug
中的可执行文件。这产生了:
C# (release): 720ms
C# (debug): 3105ms
所以我认为这就是真正存在差异的地方,你是从IDE运行调试版的C#代码。
如果您认为C ++特别慢,我将其作为优化发布版本运行并得到:
C++ (Optimised): 0ms
这并不奇怪,因为循环是空的,并且控制变量不在循环外使用,因此优化器完全删除它。为避免这种情况,我将i
声明为volatile
,结果如下:
C++ (volatile i): 2932ms
我的猜测是C#实现也删除了循环,而720ms来自其他东西;这可以解释第一次测试中时间的大部分区别。
Delphi在做什么我无法分辨,你可能会看一下生成的汇编代码。
所有上述测试均采用AMD Athlon双核5000B 2.60GHz,Windows 7 32位。
答案 1 :(得分:9)
如果这是一个基准测试,它是一个非常糟糕的基准测试,因为在这两种情况下都可以优化循环,所以你必须查看生成的机器代码才能看到正在发生的事情。如果您对C#使用发布模式,请使用以下代码
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000000; ++i){ }
sw.Stop();
Console.WriteLine(sw.Elapsed);
由JITter转换为:
push ebp
mov ebp,esp
push edi
push esi
call 67CDBBB0
mov edi,eax
xor eax,eax ; i = 0
inc eax ; ++i
cmp eax,3B9ACA00h ; i == 1000000000?
jl 0000000E ; false: jmp
mov ecx,edi
cmp dword ptr [ecx],ecx
call 67CDBC10
mov ecx,66DDAEDCh
call FFE8FBE0
mov esi,eax
mov ecx,edi
call 67CD75A8
mov ecx,eax
lea eax,[esi+4]
mov dword ptr [eax],ecx
mov dword ptr [eax+4],edx
call 66A94C90
mov ecx,eax
mov edx,esi
mov eax,dword ptr [ecx]
mov eax,dword ptr [eax+3Ch]
call dword ptr [eax+14h]
pop esi
pop edi
pop ebp
ret
答案 2 :(得分:7)
TickCount
不是一个可靠的计时器;你应该使用.Net的Stopwatch
课程。 (我不知道Delphi的等价物是什么)。
此外,您是否正在运行发布版本?
你有一个调试器吗?
答案 3 :(得分:4)
Delphi编译器向下使用for循环计数器(如果可能);上面的代码示例编译为:
Unit1.pas. 42: Tick := GetTickCount();
00489367 E8B802F8FF call GetTickCount
0048936C 8BF0 mov esi,eax
Unit1.pas.43: for I := 0 to 1000000000 do
0048936E B801CA9A3B mov eax,$3b9aca01
00489373 48 dec eax
00489374 75FD jnz $00489373
答案 4 :(得分:3)
您正在将本机代码与VM JITted代码进行比较,这是不公平的。 本机代码总是更快,因为JITter无法像本机编译器那样优化代码。
那就是说,将Delphi与C#进行比较是不公平的,Delphi二进制文件总是会赢(更快,更小,没有任何依赖等)。
Btw,我很遗憾地惊讶于这里有多少海报不知道这些差异...或者你可能只是伤害了一些试图捍卫C#的.NET狂热者,反对任何显示更好选择的东西有强>答案 5 :(得分:2)
这是c#反汇编:
DEBUG:
// int i = 0; while (++i != 1000000000) ;//==for(int i ...blah blah blah)
0000004e 33 D2 xor edx,edx
00000050 89 55 B8 mov dword ptr [ebp-48h],edx
00000053 90 nop
00000054 EB 00 jmp 00000056
00000056 FF 45 B8 inc dword ptr [ebp-48h]
00000059 81 7D B8 00 CA 9A 3B cmp dword ptr [ebp-48h],3B9ACA00h
00000060 0F 95 C0 setne al
00000063 0F B6 C0 movzx eax,al
00000066 89 45 B4 mov dword ptr [ebp-4Ch],eax
00000069 83 7D B4 00 cmp dword ptr [ebp-4Ch],0
0000006d 75 E7 jne 00000056
因为你认为这是浪费cpu
修改强>
RELEASE:
//unchecked
//{
//int i = 0; while (++i != 1000000000) ;//==for(int i ...blah blah blah)
00000032 33 D2 xor edx,edx
00000034 89 55 F4 mov dword ptr [ebp-0Ch],edx
00000037 FF 45 F4 inc dword ptr [ebp-0Ch]
0000003a 81 7D F4 00 CA 9A 3B cmp dword ptr [ebp-0Ch],3B9ACA00h
00000041 75 F4 jne 00000037
//}
修改强>
这是c ++版本:在我的机器上运行速度提高了9倍。
__asm
{
PUSH ECX
PUSH EBX
XOR ECX, ECX
MOV EBX, 1000000000
NEXT: INC ECX
CMP ECX, EBX
JS NEXT
POP EBX
POP ECX
}
答案 6 :(得分:1)
您应该附加调试器并查看每个调试器生成的机器代码。
答案 7 :(得分:0)
Delphi几乎肯定会优化该循环以反向顺序执行(即DOWNTO零而不是从零开始) - 只要Delphi确定它是“安全”的,它就会这样做,可能是因为减法或检查零比添加或检查非零数字。
如果您尝试指定循环以相反顺序执行的两种情况会发生什么?
答案 8 :(得分:0)
在Delphi中,中断条件仅在循环过程开始之前计算一次,而在C#中,中断条件在每次循环中再次计算。
这就是为什么Delphi中的循环比C#更快的原因。
答案 9 :(得分:-1)
“// int i = 0; while(++ i!= 1000000000);”
这很有意思。
while(++ i!= x)与(; i!= x; i ++)
不同区别在于while循环不执行i = 0的循环。
(尝试一下:运行这样的东西:
int i;
for (i = 0; i < 5; i++)
Console.WriteLine(i);
i = 0;
while (++i != 5)
Console.WriteLine(i);