2016-07-06 4 views
10

Ich teste die parLapplyLB() Funktion aus, um zu verstehen, was es tut, um eine Last auszugleichen. Aber ich sehe keinen Ausgleich. Zum BeispielWarum gleicht parLapplyLB die Last nicht aus?

cl <- parallel::makeCluster(2) 

system.time(
    parallel::parLapplyLB(cl, 1:4, function(y) { 
    if (y == 1) { 
     Sys.sleep(3) 
    } else { 
     Sys.sleep(0.5) 
    }})) 
## user system elapsed 
## 0.004 0.009 3.511 

parallel::stopCluster(cl) 

Wenn es um die Last wirklich balancieren, den ersten Job (Job 1), die für 3 Sekunden schläft würde auf dem ersten Knoten und die anderen drei Arbeitsplätze (Arbeitsplätze 2: 4) würde schlafen für insgesamt 1,5 Sekunden auf dem anderen Knoten. Insgesamt sollte die Systemzeit nur 3 Sekunden betragen.

Stattdessen denke ich, dass Aufträge 1 und 2 an Knoten 1 und Aufträge 3 und 4 an Knoten 2 gegeben werden. Daraus ergibt sich die Gesamtzeit 3 ​​+ 0,5 = 3,5 Sekunden. Wenn wir den gleichen Code oben mit parLapply() anstelle von parLapplyLB() ausführen, erhalten wir die gleiche Systemzeit von etwa 3,5 Sekunden.

Was verstehe ich nicht oder mache ich falsch?

+0

Ich denke, R tut nicht automatisch Lastausgleich. Ich denke, es verteilt die * Aufgaben * auf so viele Kerne wie verfügbar, unabhängig von der Zeit, die für jede Aufgabe benötigt wird, oder wenn jede Aufgabe abgeschlossen ist. Es ist nicht so, als gäbe es eine Warteschlange von Aufgaben, und wenn ein Arbeiter fertig ist, ergreift er den nächsten. Jedem Kern wurden zwei Aufgaben zugewiesen. Also 3 + 0,5 für den ersten Arbeiter und insgesamt 3,5. * würde glücklich sein, falsch zu sein * – gregmacfarlane

+3

Ja, das ist, wo die 3.5 kommt. Es gleicht die Last nicht aus. Aber die parLapplyLB behauptet, auszugleichen. – josiekre

Antwort

10

für eine Aufgabe wie das Ihre (und, was das betrifft, für jede Aufgabe, für die ich je parallel gebraucht habe) parLapplyLB ist nicht wirklich das richtige Werkzeug für den Job. Um zu sehen, warum nicht, einen Blick auf die Art und Weise, dass es umgesetzt hat:

parLapplyLB 
# function (cl = NULL, X, fun, ...) 
# { 
#  cl <- defaultCluster(cl) 
#  do.call(c, clusterApplyLB(cl, x = splitList(X, length(cl)), 
#   fun = lapply, fun, ...), quote = TRUE) 
# } 
# <bytecode: 0x000000000f20a7e8> 
# <environment: namespace:parallel> 

## Have a look at what `splitList()` does: 
parallel:::splitList(1:4, 2) 
# [[1]] 
# [1] 1 2 
# 
# [[2]] 
# [1] 3 4 

Das Problem ist, dass es die Liste der Jobs zuerst teilt sich in gleich große Teillisten, die sie dann unter den Knoten verteilt, von denen jeder Läuft lapply() auf seiner gegebenen Unterliste. Hier führt also Ihr erster Knoten Aufträge an den ersten und zweiten Eingängen aus, während der zweite Knoten Aufträge mit den dritten und vierten Eingängen ausführt.

Verwenden Sie stattdessen den vielseitigere clusterApplyLB(), die genau wie Sie arbeiten hoffen würden:

system.time(
    parallel::clusterApplyLB(cl, 1:4, function(y) { 
    if (y == 1) { 
     Sys.sleep(3) 
    } else { 
     Sys.sleep(0.5) 
    }})) 
# user system elapsed 
# 0.00 0.00 3.09 
+0

Danke! Das, wonach ich gesucht habe. Ich kann mir keinen Fall vorstellen, in dem parLapplyLB etwas anderes als parLapply produzieren würde, und deshalb bin ich mir nicht sicher, welchen Zweck es hat. – josiekre

+0

Hat 'clusterApplyLB (cl, X, fun)' das gleiche beabsichtigte Verhalten wie 'parLapplyLB'? Ich habe das auf meinem System ausprobiert, und es scheint die gleiche Ausgabe zu geben, wenn 'X' eine Liste ist, aber ich bin ein wenig nervös, indem ich' parLapplyLB' mit 'clusterApplyLB' auswechsle .. – guy

+2

nützliche Informationen hier , sowie benutzerdefiniertes parlapplyLB http://detritus.fundacioace.com/pub/books/Oreilly.Parallel.R.Oct.2011.pdf – Olivia

1

parLapplyLB wird die Last nicht balancieren, weil es einen semantischen Fehler hat. Wir haben den Fehler gefunden und eine Fehlerbehebung bereitgestellt, siehe here. Nun, es ist bis zu den R-Entwicklern, um das Update aufzunehmen.

Verwandte Themen