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# дает приблизительно 3 775 мс
Вы должны подключить отладчик и посмотреть на машинный код, сгенерированный каждым из них.
Компилятор 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
это дизассемблер 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
как вы видите, это пустая трата процессора.
РЕДАКТИРОВАТЬ:
РЕДАКТИРОВАТЬ:
//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
}
"// int i = 0; while (++ i! = 1000000000);"
Это интересно.
while (++ i! = X) не то же самое, что for (; 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);
Если это задумано как эталонный тест, это исключительно плохой тест, поскольку в обоих случаях цикл можно оптимизировать, поэтому вам нужно посмотреть на сгенерированный машинный код, чтобы увидеть, что происходит. Если вы используете режим выпуска для 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
TickCount
не является надежным таймером; вам следует использовать класс .Net Stopwatch
. (Я не знаю, что такое эквивалент Delphi).
Кроме того, используете ли вы сборку Release?
У вас есть отладчик?
Delphi почти наверняка оптимизирует этот цикл для выполнения в обратном порядке (т. Е. ВНИЗ ноль, а не ОТ нуля) - Delphi делает это всякий раз, когда определяет, что он "безопасен". "делать, предположительно потому, что вычитание или проверка на ноль быстрее, чем сложение или проверка на ненулевое число.
Что произойдет, если вы попробуете в обоих случаях указать циклы для выполнения в обратном порядке?
Delphi компилируется в собственный код, тогда как C # компилируется в код CLR, который затем транслируется во время выполнения. Тем не менее, C # действительно использует JIT-компиляцию, поэтому вы можете ожидать, что время будет более похожим, но это не дано.
Было бы полезно, если бы вы могли описать оборудование, на котором это работает (ЦП, тактовая частота).
У меня нет доступа к 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 # и запустите исполняемый файл в
и
соответственно непосредственно из командной строки. Это дало:
C# (release): 720ms
C# (debug): 3105ms
Итак, я считаю, что в этом и заключается разница, вы запускали отладочную версию кода C # из среды IDE.
Если вы думаете, что C ++ работает особенно медленно, я запустил его как оптимизированную сборку релиза и получил:
C++ (Optimised): 0ms
Это неудивительно, потому что цикл пуст, а управляющая переменная не используется вне цикла, поэтому оптимизатор удаляет его полностью. Чтобы избежать этого, я объявил i
как volatile
со следующим результатом:
C++ (volatile i): 2932ms
Я предполагаю, что реализация C # также удалила цикл и что 720 мс - это что-то еще; это может объяснить большую часть различий между таймингами в первом тесте.
Я не могу сказать, что делает Delphi, вы можете посмотреть сгенерированный код сборки, чтобы увидеть.
Все вышеперечисленные тесты проводились на AMD Athlon Dual Core 5000B 2,60 ГГц, на 32-битной Windows 7.
Вы сравниваете родной код с JIT-версией VM, и это несправедливо. Родной код ВСЕГДА будет быстрее, поскольку JITter не может оптимизировать код так, как это может сделать родной компилятор.
При этом сравнивать Delphi против C# вообще нечестно, бинарник на Delphi будет выигрывать всегда (быстрее, меньше, без всяких зависимостей и т.д.).
Btw, я, к сожалению, поражен, как много постеры здесь не знают эти различия... или, может быть, вы просто обидели некоторых .NET фанатиков, которые пытаются защитить C# от всего, что показывает, что есть лучшие варианты там.