Ich verschachtelte mehrere Ebenen von do.call
(jede selbst verwendet Funktionen in den Parametern, nicht hart-codiert) in einer parallelisierten Umgebung %dopar%
und eine Funktion von meiner äußeren Umgebung kann nicht durch die innerste Funktion gefunden werden. Ich kenne den .export
Parameter auf foreach
und benutze es, aber irgendwie verbreitet sich die benannte Funktion nicht über die gesamte Kette.Verschachtelte do.call innerhalb einer foreach% dopar% Umgebung kann keine mit export übergebene Funktion finden
Ich reduzierte meine Frage an den folgenden Testfall, der dieses Problem nicht aufweist:
library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)
simple.func <- function(a, b) {
return(a+b)
}
inner.func <- function(a, b) {
return(do.call(simple.func, list(a=a, b=b)))
}
outer.func <- function(a, b, my.func=inner.func) {
return(do.call(my.func, list(a=a, b=b)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export="simple.func") %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
Anstatt die richtige Antwort zu geben (eine Liste mit einigen Zahlen), erhalte ich:
Error in { : task 1 failed - "object 'simple.func' not found"
Hinzufügen von if (!exists("simple.func")) stop("Could not find parse.data in scope main.func")
an den Anfang jeder Funktion (Ändern des Namens des Bereichs als geeignet) ergibt, dass es inner.func
ist, die simple.func
nicht sehen - obwohl outer.func
tut sehen Sie es.
Ich habe auch ein paar Varianten des Obigen getestet, entweder mit main.func
oder outer.func
mit der nächsten Ebene Funktion hart-codiert, anstatt es von einem Parameter zu verwenden. Beide dieser Variationen funktionieren (z. B. geben das erwartete Ergebnis an), aber für den realen Fall möchte ich die Generalisierbarkeit behalten, die Unterfunktionen als Parameter zu verwenden.
# Variation number one: Replace main.func() with this version
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export=c("simple.func", "outer.func", "inner.func")) %dopar% {
return(do.call(outer.func, list(a=i, b=i+1, my.func=inner.func)))
}
return(results)
}
# Variation number two: Replace outer.func() and main.func() with these versions
outer.func <- function(a, b, my.func=inner.func) {
return(do.call(inner.func, list(a=a, b=b)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export=c("simple.func", "inner.func")) %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
ich auch simple.func
unten in der Kette passieren könnte manuell, indem sie sie als zusätzliche Parameter einschließlich, aber das sieht besonders chaotisch, und warum sollte es notwendig sein, wenn simple.func
sollte zusammen als Teil der Umwelt nur weitergegeben werden?
# Variation number three: Replace inner.func(), outer.func(), and main.func()
# with these versions
inner.func <- function(a, b, innermost.func=simple.func) {
return(do.call(innermost.func, list(a=a, b=b)))
}
outer.func <- function(a, b, my.func=inner.func,
innermost.args=list(innermost.func=simple.func)) {
return(do.call(my.func, c(list(a=a, b=b), innermost.args)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func,
innermost.args=list(innermost.func=simple.func))) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export="simple.func") %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
Hat jemand Ideen für weniger kludgy Lösungen oder die zugrunde liegende Ursache für dieses Problem?
Nur eine Anmerkung, da Ihr Code voll von ihnen ist: alle Rückkehr-Anrufe sind nicht notwendig. R gibt automatisch den Wert des letzten Ausdrucks in einer Funktion zurück. Sie brauchen nur 'return', um eine Funktion vorzeitig zu verlassen. –