Threading implicite vs performances de threading explicite [fermé]
Je parallélise une application en C # et je teste la différence de performances entre l'utilisation du thread implicite et le threading explicite. Les deux techniques utilisent la System.Threadingbibliothèque et le thread implicite est caractérisé par l'utilisation d'une Parallel.Forboucle tandis que le threading explicite implique la création, le démarrage et la jonction de threads tout en calculant la taille des blocs, en appelant la fonction de travail, etc.
J'ai constaté que j'obtenais une meilleure vitesse par rapport à la version séquentielle originale du programme en utilisant un threading explicite (environ 1,2 fois plus rapide après 50 essais) sur huit cœurs. Je comprends les différences sous-jacentes entre ces deux techniques, cependant, je ne sais pas pourquoi la version explicite semble être plus rapide. Je pensais que la version implicite serait peut-être plus rapide car les tâches seraient planifiées automatiquement, par opposition à la création manuelle de tâches et de threads. Y aurait-il une raison (à part peut-être une erreur dans mes résultats) que la version explicite serait plus rapide?
Pour référence, une version résumée du code pertinent peut être vue ci-dessous.
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);
//...
}
}
Réponses
Je pense que la comparaison n'est pas juste pour le Parallel.For, car elle doit invoquer un lambda anonyme pour chaque élément du tableau traité, tandis que l'implémentation de thread explicite implique une seule invocation de méthode par thread (la fft_workerméthode). Ce qui rend cela encore plus important, c'est que les lambdas anonymes ne peuvent pas être insérés par le compilateur C #.
Pour restaurer l'équité de la comparaison, vous pouvez soit:
- Incluez également la surcharge d'un appel lambda anonyme dans l'implémentation de thread explicite:
for (int ii = start; ii < end; ii++)
{
((Action)(() =>
{
//...
tempFFT = IterativeFFT.FFT(temp, twiddles, wSamp);
//...
}))();
}
- Réduisez la granularité (ou en d'autres termes augmentez le chunkiness) de l'implémentation de thread implicite, en remplaçant le
Parallel.Forpar le 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;
}
});
Je ne l'ai pas testé, mais ces deux suggestions devraient combler ou éliminer l'écart dans les performances des deux techniques de parallélisation.