Ecco un esperimento che ho eseguito confrontando il parallelismo in C++ e D. Ho implementato un algoritmo (uno schema di propagazione di etichette parallele per il rilevamento di comunità nelle reti) in entrambi i linguaggi, utilizzando lo stesso design: Un iteratore parallelo ottiene una funzione di handle (normalmente un chiusura) e lo applica per ogni nodo nel grafico.Perché questo codice parallelo in scala D è così grave?
Ecco l'iteratore in D, implementato utilizzando taskPool
da 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);
}
}
E questa è la funzione maniglia che viene passato:
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;
}
}
};
L'implementazione C++ 11 è quasi identico , ma utilizza OpenMP per la parallelizzazione. Quindi cosa mostrano gli esperimenti di ridimensionamento?
Qui esaminiamo scalatura debole, raddoppiando le dimensioni grafo di input mentre anche raddoppiando il numero di fili e misurando il tempo di esecuzione. L'ideale sarebbe una linea retta, ma ovviamente c'è un sovraccarico per il parallelismo. Io uso defaultPoolThreads(nThreads)
nella mia funzione principale per impostare il numero di thread per il programma D. La curva per C++ sembra buona, ma la curva per D sembra sorprendentemente negativa. Sto facendo qualcosa di sbagliato w.r.t. D parallelismo, o questo riflette male sulla scalabilità dei programmi paralleli D?
p.s. flag di compilazione
per D: rdmd -release -O -inline -noboundscheck
per C++: -std=c++11 -fopenmp -O3 -DNDEBUG
pps. Qualcosa deve essere veramente sbagliato, perché l'implementazione D è più lento in parallelo che in sequenza:
PPP. Per i curiosi, ecco gli URL clone Mercurial per entrambe le implementazioni:
Che aspetto ha la performance se l'hai fatto senza openmp? – greatwolf
Dal controllo attorno ad esso non sembra che il compilatore dmd attualmente supporti openmp. Non sembra un comparsion mele-a-mele per me se una versione utilizza openmp e l'altra versione no. – greatwolf
@greatwolf A meno che non ti fraintenda, credo che ti manchi il punto. D non ha OpenMP, ma ha la libreria 'std.parallelism', che fornisce costrutti paralleli simili. In effetti, il programma D utilizza molti core durante l'esecuzione. – clstaudt