Napisałem kilka podstawowych przykładów kodu, aby zapoznać się z PLINQ.Dlaczego moje zapytanie Aslinowane PLINQ jest szybsze niż moje nieuporządkowane?
Natrafiłem na coś dziwnego. Nie wiem, czy to błąd w moim kodzie, czy błąd w zrozumieniu PLINQ.
Dokumentacja MSDN stwierdza, że dodanie AsOrdered() zachowa kolejność połączeń pod możliwymi kosztami wydajności.
Napisałem kilka testów jednostkowych i zauważyłem wpływ na zamówienie na zestaw wyników, jak podano w dokumentacji. Ale widziałem odwrotny wpływ na wydajność.
Oto zarówno moja metoda:
public IEnumerable<int> ParallelCalculatePrimesUpTo(int maxValue)
{
return from number in Enumerable.Range(1, maxValue).AsParallel()
where IsPrime(number)
select number;
}
public IEnumerable<int> OrderedParallelCalculatePrimesUpTo(int maxValue)
{
return from number in Enumerable.Range(1, maxValue).AsParallel().AsOrdered()
where IsPrime(number)
select number;
}
A moje bardzo proste benchmarki
[TestMethod]
public void SimplisticBenchmark6()
{
var primeNumberCalculator = new PrimeNumberCalculator();
var startTime = DateTime.Now;
primeNumberCalculator.ParallelCalculatePrimesUpTo(10000000).ToList();
var totalTime = DateTime.Now - startTime;
Console.WriteLine(totalTime);
}
[TestMethod]
public void SimplisticBenchmark7()
{
var primeNumberCalculator = new PrimeNumberCalculator();
var startTime = DateTime.Now;
primeNumberCalculator.OrderedParallelCalculatePrimesUpTo(10000000).ToList();
var totalTime = DateTime.Now - startTime;
Console.WriteLine(totalTime);
}
Bez względu na to, jak często mogę uruchomić ten test, wersja nakazał bije się z nieuporządkowaną jeden. Dostaję około 4 sekundy szybciej dla zamówionego na moim czterordzeniowym komputerze. Dostaję około 18 sekund na zamówioną jedną i 22 sekundy na nieuporządkowaną. Przeprowadziłem testy dziesiątki razy w ciągu dwóch dni (z restartami między tymi dniami).
Jeśli obniżę liczbę od 10 000 000 do 6 000 000, różnice nadal występują, ale są mniej zauważalne, a jeśli obniżę je do 3 000 000, to będą mniej więcej takie same.
Próbowałem uruchomić testy w obu kolejności wykonania, a wyniki są takie same.
Oto metoda IsPrime że jest wywoływana w zapytaniu PLINQ:
// uses inneficient trial division algorithm
private bool IsPrime(int number)
{
if (number == 1)
return false;
for (int divisor = 2; divisor <= Math.Sqrt(number); divisor++)
{
if (number % divisor == 0)
return false;
}
return true;
}
Co wyjaśnia to?
Na marginesie, "DateTime" nie jest zbyt dobre dla pomiarów wydajności, użycie 'StopWatch' jest lepsze. – svick
@svick: Bardzo dobry punkt. Wiedziałem, że DateTime nie nadaje się do poważnych pomiarów, ale nie wiedział o StopWatch. Dzięki. Do kodu produkcyjnego lepiej użyć profilera, ale był to po prostu szybki i brudny kod, który napisałem, czytając dokumentację PLINQ i TPL. Następnym razem użyję StopWatch w takiej sytuacji! – Gilles
Jeśli uruchomię twój kod, zamówione jest nieco wolniej (5,67 s wobec 5,66 s dla nieuporządkowanych, uśrednione dla kilku prób), ale wariancja między próbami jest wyższa niż różnica między zamówieniem a nieuporządkowaniem, więc myślę, że nie ma statystycznie istotną różnicę w tym przypadku (przynajmniej mierzoną na moim czterordzeniowym rdzeniu). – svick