Threading implicito vs prestazioni di threading esplicito [chiuso]
Sto parallelizzando un'applicazione in C # e sto testando la differenza di prestazioni tra l'utilizzo del threading implicito rispetto al threading esplicito. Entrambe le tecniche utilizzano la System.Threadinglibreria e il threading implicito è caratterizzato dall'utilizzo di un Parallel.Forciclo mentre il threading esplicito implica la creazione, l'avvio e l'unione di thread mentre calcola anche le dimensioni dei blocchi, chiama la funzione di lavoro, ecc.
Ho scoperto di ottenere una maggiore velocità rispetto alla versione sequenziale originale del programma utilizzando il threading esplicito (circa 1,2 volte più veloce dopo 50 prove) su otto core. Capisco le differenze sottostanti tra queste due tecniche, tuttavia, non sono sicuro del motivo per cui la versione esplicita sembra essere più veloce. Ho pensato che forse la versione implicita sarebbe stata più veloce in quanto le attività sarebbero state pianificate automaticamente, al contrario delle attività manuali e della creazione di thread. Ci sarebbe una ragione (a parte forse un errore nei miei risultati) per cui la versione esplicita sarebbe più veloce?
Per riferimento, di seguito è possibile visualizzare una versione riepilogativa del codice pertinente.
float[][] stft_implicit(Complex[] x, int wSamp)
{
//...
Parallel.For(0, size, new ParallelOptions { MaxDegreeOfParallelism = MainWindow.NUM_THREADS }, ii =>
{
Complex[] tempFFT = IterativeFFT.FFT(all_temps[ii], twiddles, wSamp);
fft_results[ii] = tempFFT;
});
//...
}
float[][] stft_explicit(Complex[] x, int wSamp)
{
//...
length = (int)(2 * Math.Floor((double)N / (double)wSamp) - 1);
chunk_size = (length + MainWindow.NUM_THREADS - 1) / MainWindow.NUM_THREADS;
Thread[] threads = new Thread[MainWindow.NUM_THREADS];
for (int i = 0; i < MainWindow.NUM_THREADS; i++)
{
threads[i] = new Thread(fft_worker);
threads[i].Start(i);
}
for (int i = 0; i < MainWindow.NUM_THREADS; i++)
{
threads[i].Join();
}
//...
}
public void fft_worker(object thread_id)
{
int ID = (int)thread_id;
Complex[] temp = new Complex[wSamp];
Complex[] tempFFT = new Complex[wSamp];
int start = ID * chunk_size;
int end = Math.Min(start + chunk_size, length);
for (int ii = start; ii < end; ii++)
{
//...
tempFFT = IterativeFFT.FFT(temp, twiddles, wSamp);
//...
}
}
Risposte
Penso che il confronto non sia giusto per il Parallel.For, perché deve invocare un lambda anonimo per ogni elemento dell'array elaborato, mentre l'implementazione del threading esplicito prevede una singola invocazione del metodo per thread (il fft_workermetodo). Ciò che lo rende ancora più importante è che i lambda anonimi non possono essere inseriti inline dal compilatore C #.
Per ripristinare l'equità del confronto puoi:
- Includere l'overhead di una chiamata lambda anonima anche nell'implementazione del threading esplicito:
for (int ii = start; ii < end; ii++)
{
((Action)(() =>
{
//...
tempFFT = IterativeFFT.FFT(temp, twiddles, wSamp);
//...
}))();
}
- Riduci la granularità (o in altre parole aumenta la chunkiness) dell'implementazione del threading implicito, sostituendo il
Parallel.Forcon il Parallel.ForEach+ Partitionercombo:
Parallel.ForEach(Partitioner.Create(0, size), range =>
{
for (int ii = range.Item1; ii < range.Item2; ii++)
{
Complex[] tempFFT = IterativeFFT.FFT(all_temps[ii], twiddles, wSamp);
fft_results[ii] = tempFFT;
}
});
Non l'ho testato, ma entrambi questi suggerimenti dovrebbero colmare o eliminare il divario nelle prestazioni delle due tecniche di parallelizzazione.