Фон
Сегодня утром, выполняя тесты производительности, мы с коллегами обнаружили некоторые странные вещи, касающиеся производительности кода C # и кода VB.NET.
Мы начали сравнивать C # с вычислением простых чисел Delphi Prism и обнаружили, что Prism работает примерно на 30% быстрее. Я полагал, что код, оптимизированный для CodeGear, больше генерирует IL (exe
был примерно вдвое больше, чем C # и имел в себе все виды различных IL.)
Я решил написать тест и в VB.NET, предполагая, что компиляторы Microsoft в конечном итоге будут писать, по сути, один и тот же IL для каждого языка. Тем не менее, результат был более шокирующим: код выполнялся более чем в три раза медленнее на C #, чем VB при той же операции!
Сгенерированный IL был другим, но не очень, и я не достаточно хорош, чтобы прочитать его.
Тесты
Я включил код для каждого ниже. На моей машине VB находит 348513 простых чисел за 6,36 секунд. C # находит такое же число простых чисел в 21,76 секунд.
Технические характеристики и примечания к компьютеру
- Intel Core 2 Quad 6600 @ 2,4 ГГц
У каждой машины, на которой я тестировал, есть заметные различия в результатах тестов между C # и VB.NET.
Оба консольных приложения были скомпилированы в режиме выпуска, но в остальном никакие параметры проекта не были изменены по умолчанию, сгенерированными Visual Studio 2008.
код VB.NET
Imports System.Diagnostics
Module Module1
Private temp As List(Of Int32)
Private sw As Stopwatch
Private totalSeconds As Double
Sub Main()
serialCalc()
End Sub
Private Sub serialCalc()
temp = New List(Of Int32)()
sw = Stopwatch.StartNew()
For i As Int32 = 2 To 5000000
testIfPrimeSerial(i)
Next
sw.Stop()
totalSeconds = sw.Elapsed.TotalSeconds
Console.WriteLine(String.Format("{0} seconds elapsed.", totalSeconds))
Console.WriteLine(String.Format("{0} primes found.", temp.Count))
Console.ReadKey()
End Sub
Private Sub testIfPrimeSerial(ByVal suspectPrime As Int32)
For i As Int32 = 2 To Math.Sqrt(suspectPrime)
If (suspectPrime Mod i = 0) Then
Exit Sub
End If
Next
temp.Add(suspectPrime)
End Sub
End Module
C # код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace FindPrimesCSharp {
class Program {
List<Int32> temp = new List<Int32>();
Stopwatch sw;
double totalSeconds;
static void Main(string[] args) {
new Program().serialCalc();
}
private void serialCalc() {
temp = new List<Int32>();
sw = Stopwatch.StartNew();
for (Int32 i = 2; i <= 5000000; i++) {
testIfPrimeSerial(i);
}
sw.Stop();
totalSeconds = sw.Elapsed.TotalSeconds;
Console.WriteLine(string.Format("{0} seconds elapsed.", totalSeconds));
Console.WriteLine(string.Format("{0} primes found.", temp.Count));
Console.ReadKey();
}
private void testIfPrimeSerial(Int32 suspectPrime) {
for (Int32 i = 2; i <= Math.Sqrt(suspectPrime); i++) {
if (suspectPrime % i == 0)
return;
}
temp.Add(suspectPrime);
}
}
}
Почему C # выполняет Math.Sqrt()
медленнее, чем VB.NET?