-
Milliseconds
это баловство, надо использовать System.Diagnostics.Stopwatch
, у него на много больше точность (в >6к раз) и он умеет использовать аппаратную поддержку замеров времени (которая даёт ещё больше точности, до в 100к раз больше чем у Milliseconds
).
begin
var rc1 := 10000;
var rc2 := 1000000;
var b:real := 0;
var d:real := 0;
var sw1 := new System.Diagnostics.Stopwatch;
var sw2 := new System.Diagnostics.Stopwatch;
for var n := 1 to rc1 do // чтоб обнулить рандомные эффекты, влияющие на производительность - надо равномерно распределить их по всем тестам
begin
sw1.Start;
loop rc2 do b += 1;
sw1.Stop;
sw2.Start;
for var i := 1 to rc2 do d += 1;
sw2.Stop;
System.Console.Title := $'{n/rc1:P}'; // чтоб не скушно было ждать, так можно вытерпеть на много больший тест, раз так в 100
end;
writeln(sw1.Elapsed);
writeln(sw2.Elapsed);
readln;
end.
При чём, надо обязательно отключить отладку и запускать по Shift+F9, иначе результат может очень сильно отличатся. + желательно проверять время от времени, ибо паскаль любит включать отладку снова (обычно, если запустить без Shift+F9).
Результаты у меня:
00:00:18.3940394
00:00:20.6404646
Далее, тесты это прикольно и полезно, но тут ведь всё прозрачнее некуда, можно посмотреть напрямую какой код генерирует for
, а какой loop
. Я для этого использую DotPeek. Вот вся последняя программа:
public static void $Main()
{
int num1 = 10000;
int num2 = 1000000;
double num3 = 0.0;
double num4 = 0.0;
Stopwatch stopwatch1 = new Stopwatch();
Stopwatch stopwatch2 = new Stopwatch();
int num5 = num1;
int num6 = 1;
if (num6 <= num5)
{
while (true)
{
stopwatch1.Start();
int num7 = num2;
int num8 = 1;
if (num8 <= num7)
{
while (true)
{
++num3;
if (num8 < num7)
++num8;
else
break;
}
}
stopwatch1.Stop();
stopwatch2.Start();
int num9 = num2;
int num10 = 1;
if (num10 <= num9)
{
while (true)
{
++num4;
if (num10 < num9)
++num10;
else
break;
}
}
stopwatch2.Stop();
Console.Title = string.Format("{0:P}", (object) ((double) num6 / (double) num1));
if (num6 < num5)
++num6;
else
break;
}
}
PABCSystem.PABCSystem.Writeln((object) stopwatch1.Elapsed);
PABCSystem.PABCSystem.Writeln((object) stopwatch2.Elapsed);
PABCSystem.PABCSystem.Readln();
}
И её IL код:
.method public static void
$Main() cil managed
{
.maxstack 8
.locals init (
[0] int32 num1,
[1] int32 num2,
[2] float64 num3,
[3] float64 num4,
[4] class [System]System.Diagnostics.Stopwatch stopwatch1,
[5] class [System]System.Diagnostics.Stopwatch stopwatch2,
[6] int32 num6,
[7] int32 num5,
[8] int32 num8,
[9] int32 num7,
[10] int32 num10,
[11] int32 num9
)
// [34 7 - 34 23]
IL_0000: ldc.i4 10000 // 0x00002710
IL_0005: stloc.0 // num1
// [35 7 - 35 25]
IL_0006: ldc.i4 1000000 // 0x000f4240
IL_000b: stloc.1 // num2
// [36 7 - 36 24]
IL_000c: ldc.r8 0.0
IL_0015: stloc.2 // num3
// [37 7 - 37 24]
IL_0016: ldc.r8 0.0
IL_001f: stloc.3 // num4
// [38 7 - 38 45]
IL_0020: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0025: stloc.s stopwatch1
// [39 7 - 39 45]
IL_0027: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_002c: stloc.s stopwatch2
IL_002e: ldc.i4.1
IL_002f: stloc.s V_6
// [40 7 - 40 22]
IL_0031: ldloc.0 // num1
IL_0032: stloc.s num5
// [41 7 - 41 19]
IL_0034: ldc.i4.1
IL_0035: stloc.s num6
// [42 7 - 42 24]
IL_0037: ldloc.s num6
IL_0039: ldloc.s num5
IL_003b: cgt
IL_003d: ldc.i4.0
IL_003e: ceq
IL_0040: brfalse IL_0108
// start of loop, entry point: IL_0045
// [46 11 - 46 29]
IL_0045: ldloc.s stopwatch1
IL_0047: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_004c: nop
IL_004d: ldc.i4.1
IL_004e: stloc.s V_8
// [47 11 - 47 26]
IL_0050: ldloc.1 // num2
IL_0051: stloc.s num7
// [48 11 - 48 23]
IL_0053: ldc.i4.1
IL_0054: stloc.s num8
// [49 11 - 49 28]
IL_0056: ldloc.s num8
IL_0058: ldloc.s num7
IL_005a: cgt
IL_005c: ldc.i4.0
IL_005d: ceq
IL_005f: brfalse IL_0086
// start of loop, entry point: IL_0064
// [53 15 - 53 21]
IL_0064: ldloc.2 // num3
IL_0065: ldc.r8 1
IL_006e: add
IL_006f: stloc.2 // num3
// [54 15 - 54 31]
IL_0070: ldloc.s num8
IL_0072: ldloc.s num7
IL_0074: clt
IL_0076: brfalse IL_0086
// [55 17 - 55 23]
IL_007b: ldloc.s num8
IL_007d: ldc.i4.1
IL_007e: add
IL_007f: stloc.s num8
IL_0081: br IL_0064
// end of loop
// [60 11 - 60 28]
IL_0086: ldloc.s stopwatch1
IL_0088: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_008d: nop
// [61 11 - 61 29]
IL_008e: ldloc.s stopwatch2
IL_0090: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0095: nop
IL_0096: ldc.i4.1
IL_0097: stloc.s V_10
// [62 11 - 62 26]
IL_0099: ldloc.1 // num2
IL_009a: stloc.s num9
// [63 11 - 63 24]
IL_009c: ldc.i4.1
IL_009d: stloc.s num10
// [64 11 - 64 29]
IL_009f: ldloc.s num10
IL_00a1: ldloc.s num9
IL_00a3: cgt
IL_00a5: ldc.i4.0
IL_00a6: ceq
IL_00a8: brfalse IL_00cf
// start of loop, entry point: IL_00ad
// [68 15 - 68 21]
IL_00ad: ldloc.3 // num4
IL_00ae: ldc.r8 1
IL_00b7: add
IL_00b8: stloc.3 // num4
// [69 15 - 69 32]
IL_00b9: ldloc.s num10
IL_00bb: ldloc.s num9
IL_00bd: clt
IL_00bf: brfalse IL_00cf
// [70 17 - 70 24]
IL_00c4: ldloc.s num10
IL_00c6: ldc.i4.1
IL_00c7: add
IL_00c8: stloc.s num10
IL_00ca: br IL_00ad
// end of loop
// [75 11 - 75 28]
IL_00cf: ldloc.s stopwatch2
IL_00d1: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_00d6: nop
// [76 11 - 76 91]
IL_00d7: ldstr "{0:P}"
IL_00dc: ldloc.s num6
IL_00de: conv.r8
IL_00df: ldloc.0 // num1
IL_00e0: conv.r8
IL_00e1: div
IL_00e2: box [mscorlib]System.Double
IL_00e7: call string [mscorlib]System.String::Format(string, object)
IL_00ec: call void [mscorlib]System.Console::set_Title(string)
IL_00f1: nop
// [77 11 - 77 27]
IL_00f2: ldloc.s num6
IL_00f4: ldloc.s num5
IL_00f6: clt
IL_00f8: brfalse IL_0108
// [78 13 - 78 19]
IL_00fd: ldloc.s num6
IL_00ff: ldc.i4.1
IL_0100: add
IL_0101: stloc.s num6
IL_0103: br IL_0045
// end of loop
// [83 7 - 83 65]
IL_0108: ldloc.s stopwatch1
IL_010a: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
IL_010f: box [mscorlib]System.TimeSpan
IL_0114: call void PABCSystem.PABCSystem::Writeln(object)
IL_0119: nop
// [84 7 - 84 65]
IL_011a: ldloc.s stopwatch2
IL_011c: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
IL_0121: box [mscorlib]System.TimeSpan
IL_0126: call void PABCSystem.PABCSystem::Writeln(object)
IL_012b: nop
// [85 7 - 85 37]
IL_012c: call void PABCSystem.PABCSystem::Readln()
IL_0131: nop
IL_0132: ret
} // end of method Program::$Main
Теперь отдельно код loop
:
int num7 = num2;
int num8 = 1;
if (num8 <= num7)
{
while (true)
{
++num3;
if (num8 < num7)
++num8;
else
break;
}
}
// [40 7 - 40 22]
IL_0031: ldloc.0 // num1
IL_0032: stloc.s num5
// [41 7 - 41 19]
IL_0034: ldc.i4.1
IL_0035: stloc.s num6
// [42 7 - 42 24]
IL_0037: ldloc.s num6
IL_0039: ldloc.s num5
IL_003b: cgt
IL_003d: ldc.i4.0
IL_003e: ceq
IL_0040: brfalse IL_0108
// start of loop, entry point: IL_0045
// [46 11 - 46 29]
IL_0045: ldloc.s stopwatch1
IL_0047: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_004c: nop
IL_004d: ldc.i4.1
IL_004e: stloc.s V_8
// [47 11 - 47 26]
IL_0050: ldloc.1 // num2
IL_0051: stloc.s num7
// [48 11 - 48 23]
IL_0053: ldc.i4.1
IL_0054: stloc.s num8
// [49 11 - 49 28]
IL_0056: ldloc.s num8
IL_0058: ldloc.s num7
IL_005a: cgt
IL_005c: ldc.i4.0
IL_005d: ceq
IL_005f: brfalse IL_0086
// start of loop, entry point: IL_0064
// [53 15 - 53 21]
IL_0064: ldloc.2 // num3
IL_0065: ldc.r8 1
IL_006e: add
IL_006f: stloc.2 // num3
// [54 15 - 54 31]
IL_0070: ldloc.s num8
IL_0072: ldloc.s num7
IL_0074: clt
IL_0076: brfalse IL_0086
// [55 17 - 55 23]
IL_007b: ldloc.s num8
IL_007d: ldc.i4.1
IL_007e: add
IL_007f: stloc.s num8
IL_0081: br IL_0064
// end of loop
И for
:
int num9 = num2;
int num10 = 1;
if (num10 <= num9)
{
while (true)
{
++num4;
if (num10 < num9)
++num10;
else
break;
}
}
// [62 11 - 62 26]
IL_0099: ldloc.1 // num2
IL_009a: stloc.s num9
// [63 11 - 63 24]
IL_009c: ldc.i4.1
IL_009d: stloc.s num10
// [64 11 - 64 29]
IL_009f: ldloc.s num10
IL_00a1: ldloc.s num9
IL_00a3: cgt
IL_00a5: ldc.i4.0
IL_00a6: ceq
IL_00a8: brfalse IL_00cf
// start of loop, entry point: IL_00ad
// [68 15 - 68 21]
IL_00ad: ldloc.3 // num4
IL_00ae: ldc.r8 1
IL_00b7: add
IL_00b8: stloc.3 // num4
// [69 15 - 69 32]
IL_00b9: ldloc.s num10
IL_00bb: ldloc.s num9
IL_00bd: clt
IL_00bf: brfalse IL_00cf
// [70 17 - 70 24]
IL_00c4: ldloc.s num10
IL_00c6: ldc.i4.1
IL_00c7: add
IL_00c8: stloc.s num10
IL_00ca: br IL_00ad
// end of loop
Я внимателно рассмотрел 2 кода и провёл ещё тестов… И я не понял откуда те 2 сек разницы. IL коды вроде одинаковые. А те 2 сек как то рандомно перемещаются между loop
и for
(если их менять местами целиком или по частям). Но это всё же не случайность, их даёт стабильно. В общем передаю эстафету вам, братья форумчане))