Ho scritto un codice di esempio di base per familiarizzare con PLINQ.Perché la query PLINQ di ASOrder è più veloce della mia non ordinata
Mi sono imbattuto in qualcosa di strano. Non so se si tratta di un errore nel mio codice o di un errore nella mia comprensione di PLINQ.
La documentazione MSDN afferma che l'aggiunta di AsOrdered() manterrà l'ordine della chiamata al costo possibile delle prestazioni.
Ho scritto alcuni test unitari e ho notato l'effetto sull'ordine sul set di risultati come indicato nella documentazione. Ma ho visto l'effetto inverso sulle prestazioni.
Ecco sia il mio metodo:
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;
}
E i miei punti di riferimento molto semplici
[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);
}
Non importa quante volte ho eseguito questo test, la versione ordinata batte quella ordinata. Presto circa 4 secondi più veloce per quello ordinato sul mio computer quad core. Sto ottenendo circa 18 secondi per quello ordinato e 22 secondi per quello non ordinato. Ho eseguito i test decine di volte nel corso di due giorni (con riavvii tra quei giorni).
Se abbasso il numero da 10.000.000 a 6.000.000, le differenze sono ancora lì ma meno evidenti e se lo riduco a 3 000 000, è all'incirca la stessa velocità.
Ho provato a eseguire i test in entrambi gli ordini e i risultati sono gli stessi.
Ecco il metodo isPrime che viene chiamato nella query 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;
}
Cosa spiega questo?
Come nota a margine, 'DateTime' non è molto buono per le misurazioni delle prestazioni, utilizzando' StopWatch' è meglio. – svick
@svick: ottimo punto. Sapevo che DateTime non andava bene per le misurazioni serie ma non sapeva di StopWatch. Grazie. Per il codice di produzione è meglio usare un profiler, ma questo era solo il codice veloce e sporco che ho scritto mentre leggevo i documenti PLINQ e TPL. La prossima volta userò StopWatch in una situazione del genere! – Gilles
Se eseguo il codice, ordinato è leggermente più lento (5.67 s contro 5.66 s per non ordinato, mediato su diversi tentativi), ma la varianza tra i tentativi è superiore alla differenza tra ordinato e non ordinato, quindi penso che non ci sia differenza statisticamente significativa in questo caso (almeno come misurata sul mio quad-core). – svick