2016-01-07 6 views
9

Ich habe ein Problem mit foreach, dass ich einfach nicht herausfinden kann. Der folgende Code nicht auf zwei Windows-Computer habe ich versucht, aber erfolgreich auf drei Linux-Rechnern, die alle die gleichen Versionen von R und doParallel ausgeführt wird:doParallel "foreach" inkonsistent Objekte aus der übergeordneten Umgebung erbt: "Fehler in {: Task 1 fehlgeschlagen -" konnte Funktion nicht finden ... "

library("doParallel") 
registerDoParallel(cl=2,cores=2) 

f <- function(){return(10)} 
g <- function(){ 
    r = foreach(x = 1:4) %dopar% { 
     return(x + f()) 
    } 
    return(r) 
} 
g() 

auf diesen zwei Windows-Computern, wird der folgende Fehler zurückgegeben:

Error in { : task 1 failed - "could not find function "f"" 

Dies funktioniert jedoch gut auf den Linux-Computern, und funktioniert auch gut mit% do% anstelle von% dopar% und funktioniert gut für eine normale for-Schleife.

Dasselbe gilt für Variablen, z. Einstellung i <- 10 und return(x + f()) mit return(x + i)

Für andere mit dem gleichen Problem zu ersetzen, zwei Abhilfen sind:

1) die benötigten Funktionen und Variablen mit .export explizit importieren:

r = foreach(x=1:4, .export="f") %dopar% 

2) importieren alle globale Objekte:

r = foreach(x=1:4, .export=ls(.GlobalEnv)) %dopar% 

Das Problem mit diesen Problemumgehungen ist, dass sie nicht Th sind Das stabilste für ein großes, sich aktiv entwickelndes Paket. In jedem Fall soll sich foreach wie für verhalten.

Irgendwelche Ideen, was das verursacht und ob es eine Lösung gibt?


Versionsinfo des Computers, der die Funktion funktioniert auf:

R version 3.2.2 (2015-08-14) 
Platform: x86_64-pc-linux-gnu (64-bit) 
Running under: CentOS release 6.5 (Final) 

other attached packages: 
[1] doParallel_1.0.10 iterators_1.0.8 foreach_1.4.3 

Der Computer die Funktion nicht funktioniert:

R version 3.2.2 (2015-08-14) 
Platform: x86_64-w64-mingw32/x64 (64-bit) 
Running under: Windows 7 x64 (build 7601) Service Pack 1 

other attached packages: 
[1] doParallel_1.0.10 iterators_1.0.8 foreach_1.4.3 
+3

Wo ist die Funktion 'f()' in Ihrem Beispielcode? Basierend auf dem, was Sie zur Verfügung gestellt haben, scheint es, als ob der Windows-Rechner den richtigen Fehler gibt, da 'f' keine Funktion ist, sondern eine Zahl. – brittenb

+0

Von doParallel Vignette: "Um Multicore-ähnliche Funktionalität zu verwenden, würden wir die Anzahl der zu verwendenden Kerne angeben (aber beachten, dass unter Windows versucht, mehr als einen Kern mit parallelen Ergebnissen in einem Fehler zu verwenden)" Ie: windows does nicht implementieren etwas wie 'fork' von doParallel verwendet, ist die Problemumgehung zu starten eine gesamte neue R-Sitzung, um den Job in, IIRC kopieren Sie die übergeordnete Umgebung, hier die' g' Funktion env und nicht Global. – Tensibai

+0

@brittenb Sorry, ich habe eine unvollständige Änderung vorgenommen; Ich wollte f = function() {return (10)} machen. Bearbeiten des Originals – sssheridan

Antwort

9

@Tensibai ist richtig. Wenn Sie versuchen, doParallel unter Windows zu verwenden, müssen Sie die Funktionen exportieren, die Sie verwenden möchten, die nicht im aktuellen Bereich sind. Nach meiner Erfahrung ist die Art, wie ich diese Arbeit gemacht habe, mit dem folgenden (redigierten) Beispiel.

format_number <- function(data) { 
    # do stuff that requires stringr 
} 

format_date_time <- function(data) { 
    # do stuff that requires stringr 
} 

add_direction_data <- function(data) { 
    # do stuff that requires dplyr 
} 

parse_data <- function(data) { 
    voice_start <- # vector of values 
    voice_end <- # vector of values 
    target_phone_numbers <- # vector of values 
    parse_voice_block <- function(block_start, block_end, number) { 
    # do stuff 
    } 

    number_of_cores <- parallel::detectCores() - 1 
    clusters <- parallel::makeCluster(number_of_cores) 
    doParallel::registerDoParallel(clusters) 
    data_list <- foreach(i = 1:length(voice_start), .combine=list, 
         .multicombine=TRUE, 
         .export = c("format_number", "format_date_time", "add_direction_data"), 
         .packages = c("dplyr", "stringr")) %dopar% 
         parse_voice_block(voice_start[i], voice_end[i], target_phone_numbers[i]) 
    doParallel::stopCluster(clusters) 
    output <- plyr::rbind.fill(data_list) 
} 

Da die ersten drei Funktionen in meinem aktuellen Umfeld nicht enthalten sind, würde doParallel sie ignorieren, wenn die neuen Instanzen von R Anheizen, aber es würde wissen, wo parse_voice_block zu finden, da es in dem aktuellen Bereich ist. Darüber hinaus müssen Sie angeben, welche Pakete in jeder neuen Instanz von R geladen werden sollen. Wie Tensibai sagte, liegt dies daran, dass Sie nicht den Forkprozess ausführen, sondern stattdessen mehrere Instanzen von R gleichzeitig starten und Befehle ausführen.

+1

Sie sollten 'stopCluster (clusters)' anstelle von 'stopImplicitCluster()' verwenden, da Sie 'makeCluster' explizit aufrufen. Wenn Sie '.combine = list' verwenden, erhalten Sie auch Listen innerhalb von Listen, wenn Sie mehr als 100 Aufgaben haben. –

+0

@SteveWeston Herzlichen Dank, danke dafür! – brittenb

+0

@SteveWeston Buchstäblich 6 Tage nachdem du mir das gesagt hast, liefere ich einen Code mit 'doParallel' und versuche am Ende' plind :: rbind.fill (data_list) 'zu finden und es scheitert. Ich kann nicht herausfinden, warum für etwa eine Stunde und dann merke ich endlich, dass es wegen dieser Bemerkung ist. Also nochmals vielen Dank für die Aufmerksamkeit. – brittenb

5

Es ist ziemlich bedauerlich, dass, wenn Sie sich registrieren doParallel mit:

registerDoParallel(2) 

dann doParallel verwendet mclapply auf Linux und Mac OS X, aber clusterApplyLB mit einem implizit erstellt Cluster-Objekt unter Windows.Dies führt häufig dazu, dass Code unter Linux funktioniert, aber unter Windows fehlschlägt, weil die Worker Klone des Masters sind, wenn mclapply aufgrund fork verwendet wird. Aus diesem Grunde teste ich in der Regel meinen Code verwendet:

cl <- makePSOCKcluster(2) 
registerDoParallel(cl) 

um sicherzustellen, dass ich lade alle notwendigen Pakete und Exportieren alle notwendigen Funktionen und Variablen, und dann zu registerDoParallel(2) wechsle den Vorteil mclapply auf Plattformen zu erhalten das unterstützt es.

Beachten Sie, dass die .packages und .export Optionen werden ignoriert, wenn doParallelmclapply verwendet, aber ich empfehle sie immer für die Portabilität.


Die Auto-Export-Funktion von foreach nicht ganz so reibungslos funktioniert, wenn es in einer Funktion verwenden, da foreach eher konservativ ist, was mit Auto-Export. Es scheint ziemlich sicher zu sein, Variablen und Funktionen, die in der aktuellen Umgebung definiert sind, automatisch zu exportieren, aber außerhalb davon erscheint es mir wegen der Komplexität der Scoping-Regeln von R gefährlich.

neige ich dazu, mit Ihrem Kommentar, dass Ihre beiden Umgehungen sind nicht sehr stabil für ein aktiv entwickelt Paket zustimmen, aber wenn f und g in Paket foo definiert sind, dann sollten Sie die foreach .package Option die laden verpacken foo auf die Arbeiter:

g <- function(){ 
    r = foreach(x = 1:4, .packages='foo') %dopar% { 
     return(x + f()) 
    } 
    return(r) 
} 

Dann f wird im Rahmen der g obwohl es weder implizit oder explizit von foreach exportiert wird. Dies setzt jedoch voraus, dass f eine exportierte Funktion von foo ist (im Gegensatz zu einer internen Funktion), da der von den Worker ausgeführte Code nicht in foo definiert ist, sodass er nur auf exportierte Funktionen zugreifen kann. (Sorry für die Verwendung des Begriffs "Export" auf zwei verschiedene Arten, aber es ist schwer zu vermeiden.)

Ich bin immer daran interessiert, Kommentare wie Ihre zu hören, weil ich mich immer frage, ob die Auto-Export-Regeln sein sollten optimiert. In diesem Fall denke ich, dass, wenn eine foreach-Schleife von einer Funktion ausgeführt wird, die in einem Paket definiert ist, die Cluster-Mitarbeiter dieses Paket automatisch laden sollten, ohne die Option .packages zu verwenden. Ich werde versuchen, das zu untersuchen und vielleicht das nächste Release von doParallel und doSNOW hinzuzufügen.

Verwandte Themen