Oto jeden z eksperymentów, które przeprowadziłem porównując paralelizm w C++ i D. Zaimplementowałem algorytm (schemat propagacji etykiety równoległej do wykrywania społeczności w sieciach) w obu językach, używając tego samego projektu: iterator równoległy uzyskuje funkcję uchwytu (zwykle zamknięcie) i stosuje go dla każdego węzła na wykresie.Dlaczego ten kod równoległy w skali D tak źle?
Oto iterator D, realizowane z wykorzystaniem taskPool
z 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);
}
}
i jest to funkcja, która jest przekazywana rękojeść:
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;
}
}
};
Realizacja C++ 11 jest prawie identyczny , ale używa OpenMP do równoległości. Co pokazują eksperymenty skalowania?
Tutaj badam słabe skalowanie, podwojenie rozmiaru wykresu wejście jednocześnie podwajając liczbę wątków i pomiar czasu pracy. Ideał byłby linią prostą, ale oczywiście istnieje pewne obciążenie dla równoległości. Używam defaultPoolThreads(nThreads)
w mojej głównej funkcji do ustawiania liczby wątków dla programu D. Krzywa dla C++ wygląda dobrze, ale krzywa dla D wygląda zaskakująco źle. Czy robię coś złego w.r.t. Równoległość D, czy też źle odzwierciedla skalowalność równoległych programów D?
p.s. flagi kompilatora
dla D: rdmd -release -O -inline -noboundscheck
dla C++: -std=c++11 -fopenmp -O3 -DNDEBUG
PPS. Coś musi być naprawdę źle, ponieważ realizacja D jest wolniejszy niż równolegle kolejno:
PPP. Dla ciekawskich, oto Mercurial urls klonów dla obu implementacjach:
Jak wygląda wydajność, jeśli zrobiłeś to bez OpenMP? – greatwolf
Od sprawdzania wokół niego nie wygląda na to, że kompilator dmd obsługuje obecnie openmp. Nie wydaje mi się, żebym porównał jabłka do jabłka, jeśli jedna wersja używa openmp, a inna nie. – greatwolf
@greatwolf Chyba że źle cię zrozumiałem, wierzę, że brakuje ci sensu. D nie ma OpenMP, ale ma bibliotekę 'std.parallelism', która dostarcza podobnych równoległych konstrukcji. W rzeczywistości program D wykorzystuje wiele rdzeni podczas działania. – clstaudt