Parallele Aufgaben bekommen bessere Leistungen mit boost::thread als mit ppl oder OpenMP
Ich habe ein C++ - Programm, das könnte parallelisiert werden. Ich verwende Visual Studio 2010, 32-bit-Kompilierung.
Kurz die Struktur des Programms ist im folgenden
#define num_iterations 64 //some number
struct result
{
//some stuff
}
result best_result=initial_bad_result;
for(i=0; i<many_times; i++)
{
result *results[num_iterations];
for(j=0; j<num_iterations; j++)
{
some_computations(results+j);
}
//update best_result;
}
Da jeder some_computations()
unabhängig ist(einige Globale Variablen Lesen, aber keine globalen Variablen geändert) ich parallelisierte die innere for
-Schleife.
Mein Erster Versuch war mit boost::thread,
thread_group group;
for(j=0; j<num_iterations; j++)
{
group.create_thread(boost::bind(&some_computation, this, result+j));
}
group.join_all();
Die Ergebnisse waren gut, aber ich beschlossen, zu versuchen mehr.
Ich habe versucht, die OpenMP Bibliothek
#pragma omp parallel for
for(j=0; j<num_iterations; j++)
{
some_computations(results+j);
}
Waren die Ergebnisse schlechter als die boost::thread
's lieben.
Dann habe ich versucht die ppl Bibliothek und verwendet werden parallel_for()
:
Concurrency::parallel_for(0,num_iterations, [=](int j) {
some_computations(results+j);
})
Die Ergebnisse waren die schlimmsten.
Fand ich dieses Verhalten ziemlich überraschend. Da OpenMP und ppl sind konzipiert für die Parallelisierung, ich hätte erwartet, dass bessere Ergebnisse, als boost::thread
. Bin ich falsch?
Warum ist boost::thread
mir bessere Ergebnisse?
- Könnten Sie bitte quantifizieren Sie "besser", z.B. bieten die Ausführungszeiten gegenüber der Anzahl der threads? Mit
boost::thread
Sie erstellen mit 64 threads. OpenPM verwendet ein team von worker-threads, deren Anzahl ist standardmäßig die Anzahl der virtuellen CPUs. PPL verwendet auch einen thread-pool und haben sogar höheren Aufwand als OpenMP, da es implementiert auch die Arbeit balancing. - Ich benutzte die gleiche Anzahl (32 oder 64) für jeden Versuch, vielleicht, wie Sie darauf hingewiesen, mit OpenMP und ppl, ich könnte bessere Ergebnisse, wenn Sie die Anzahl der threads gleich der Anzahl der Kerne. Ich werde es versuchen.
- Es ist fast unmöglich die Frage zu beantworten, wie es stand. Was ist
some_computations
tun? Ich es möglich, Konflikte irgendwo (die Treffer die verschiedenen Bibliotheken unterschiedlich aus, wenn z.B. openmp hat tatsächlich geringer Aufwand, aber Sie haben eine Menge von Schreibzugriffen auf gemeinsam genutzten cachelines die resultierende cache-Invalidierung frenzy kann tatsächlich machen es langsamer)? Wie lange dauert es, bis laufen durch die parallelisierte block für jede Variante
Du musst angemeldet sein, um einen Kommentar abzugeben.
OpenMP oder die PPL machen keine solche Sache als pessimistisch. Sie tun nur, was Ihnen gesagt wird, aber es gibt einige Dinge, die Sie berücksichtigen sollten, wenn Sie versuchen, paralellize Schleifen.
Ohne zu sehen, wie Sie umgesetzt werden diese Dinge, es ist schwer zu sagen, was die wirkliche Ursache sein kann.
Auch wenn die Vorgänge in jeder iteration haben einige der Abhängigkeit von anderen Iterationen in der Schleife, dann wird dies zu Konflikten, die Dinge verlangsamen. Sie haben nicht gezeigt, was Ihre
some_operation
Funktion eigentlich tut, so ist es schwer zu sagen, ob es Abhängigkeiten.Einer Schleife, die kann wirklich parallelisiert werden können, haben in jeder iteration ausgeführt werden, völlig unabhängig von allen anderen Iterationen, ohne gemeinsam genutzten Speicher zugegriffen wird in beliebigen Iterationen. Am besten, Sie schreiben würdest, die Sachen zu lokalen Variablen und kopieren Sie dann am Ende.
Nicht alle Schleifen parallelisiert werden kann, ist es sehr abhängig von der Art der Arbeit, die geleistet wird.
Beispielsweise etwas, das ist gut für die Parallelisierung ist die Arbeit getan, jeder pixel ein Bildschirm-Puffer. Jedes pixel ist völlig unabhängig von allen anderen Pixeln, und daher, ein thread kann eine iteration einer Schleife und die Arbeit ohne Sie gemacht werden, warten auf shared-memory-oder Daten-Abhängigkeiten innerhalb der Schleife zwischen den Iterationen.
Auch, wenn Sie eine zusammenhängende array, dieses array kann teilweise in einer cache-Zeile, und Bearbeiten Sie element 5 in die Gewinde Ein und dann ändern element 6 in thread B, erhalten Sie eventuell die cache-Konflikte, die auch verlangsamen die Dinge, als würden diese Ihren Wohnsitz in der gleichen cache-Zeile. Ein Phänomen, bekannt als false-sharing.
Es gibt viele Aspekte zu denken, wenn dabei die Schleife zu parallelisieren.
some_operation
nimmt einen Versatz in ein array, und das array aufgeteilt wird, mehrere threads. Ich weiß nicht, dass entweder die PPL oder OpenMP machen kann, keine garantuees bist du nicht schreiben, das array, oder irgendetwas anderes zu schreiben ist, dass array. Daher meine Antwort ändert sich nicht.In kurzen Worten,
openMP
basiert im wesentlichen auf einer gemeinsam genutzten Speicher, mit zusätzlichen Kosten von tasking management und Speicher-management.ppl
ist entworfen, um generische Muster von gemeinsamen Datenstrukturen und algorithmen, es bringt zusätzliche Komplexität, Kosten. Beide von Ihnen haben zusätzliche CPU-Kosten, die aber Ihre einfache falling downboost
threads nicht (boost
threads sind nur einfache API-Verpackung). Das ist, warum die beiden von Ihnen sind langsamer als Ihreboost
version. Und da die exampled Berechnung ist unabhängig für jeden anderen, ohne Synchronisation,openMP
sollte in der Nähe derboost
version.Tritt es in einfachen Szenarien, aber für komplizierte Szenarien mit komplizierten layout-Daten und-algorithmen, es sollte Kontext-abhängig.