Hier ist ein Experiment zum Vergleich der Parallelität in C++ und D. Ich implementierte einen Algorithmus (ein paralleles Label-Propagation-Schema für die Community-Erkennung in Netzwerken) in beiden Sprachen mit dem gleichen Design: Ein paralleler Iterator bekommt eine Handle-Funktion (normalerweise a Schließung) und wendet es für jeden Knoten in der Grafik an. HierWarum skaliert dieser parallele Code in D so schlecht?
ist der Iterator in D, umgesetzt mit taskPool
von std.parallelism
:
/**
* Iterate in parallel over all nodes of the graph and call handler (lambda closure).
*/
void parallelForNodes(F)(F handle) {
foreach (node v; taskPool.parallel(std.range.iota(z))) {
// call here
handle(v);
}
}
und dies ist der Griff-Funktion, die übergeben wird:
auto propagateLabels = (node v){
if (active[v] && (G.degree(v) > 0)) {
integer[label] labelCounts;
G.forNeighborsOf(v, (node w) {
label lw = labels[w];
labelCounts[lw] += 1; // add weight of edge {v, w}
});
// get dominant label
label dominant;
integer lcmax = 0;
foreach (label l, integer lc; labelCounts) {
if (lc > lcmax) {
dominant = l;
lcmax = lc;
}
}
if (labels[v] != dominant) { // UPDATE
labels[v] = dominant;
nUpdated += 1; // TODO: atomic update?
G.forNeighborsOf(v, (node u) {
active[u] = 1;
});
} else {
active[v] = 0;
}
}
};
Die C++ 11 Umsetzung ist nahezu identisch , verwendet jedoch OpenMP zur Parallelisierung. Was zeigen die Skalierungsexperimente?
Hier untersuche ich schwach Skalierung, die Eingangsdiagrammgröße zu verdoppeln und gleichzeitig die Anzahl der Threads zu verdoppeln und die Laufzeit zu messen. Das Ideal wäre eine gerade Linie, aber natürlich gibt es einen gewissen Mehraufwand für die Parallelität. Ich verwende defaultPoolThreads(nThreads)
in meiner Hauptfunktion, um die Anzahl der Threads für das D-Programm festzulegen. Die Kurve für C++ sieht gut aus, aber die Kurve für D sieht überraschend schlecht aus. Mache ich etwas falsches w.r.t. D Parallelität oder spiegelt dies die Skalierbarkeit von parallelen D-Programmen wider?
p.s. Compiler-Flags
für D: rdmd -release -O -inline -noboundscheck
für C++: -std=c++11 -fopenmp -O3 -DNDEBUG
pps. Es muss etwas wirklich falsch sein, weil die D-Implementierung ist langsamer parallel als aufeinander folgend:
PPPs. Für die Neugierigen, hier sind die Mercurial Klon Urls für beide Implementierungen:
Wie sieht die Leistung aus, wenn Sie ohne openmp arbeiten? – greatwolf
Von der Überprüfung her sieht es nicht so aus, als ob der DMD-Compiler derzeit openmp unterstützt. Es scheint mir kein Vergleich zwischen Äpfeln und Äpfeln zu sein, wenn eine Version openmp benutzt und andere nicht. – greatwolf
@greatwolf Wenn ich dich nicht missverstehe, glaube ich, dass du den Punkt verpasst hast. D hat kein OpenMP, aber es hat die Bibliothek 'std.parallelism', die ähnliche parallele Konstrukte bereitstellt. Tatsächlich verwendet das D-Programm beim Ausführen viele Kerne. – clstaudt