2013-02-04 10 views
13

Pracuję z mclapply z pakietu multicore (w systemie Ubuntu) i piszę funkcję, która wymaga, aby wyniki mclapply(x, f) zostały zwrócone w kolejności (tj. f(x[1]), f(x[2]), ...., f(x[n])).Czy mclapply gwarantuje, że zwróci wyniki w kolejności?

# multicore doesn't work on Windows 

require(multicore) 
unlist(mclapply(
    1:10, 
    function(x){ 
     Sys.sleep(sample(1:5, size = 1)) 
     identity(x)}, mc.cores = 2)) 

[1] 1 2 3 4 5 6 7 8 9 10 

Powyższy kod wydaje się sugerować, że mclapply zwraca wyniki w tej samej kolejności co lapply.

Jednakże, jeśli to założenie jest błędne, będę musiał poświęcić wiele czasu na refaktoryzację mojego kodu, więc mam nadzieję uzyskać pewność od kogoś bardziej zaznajomionego z tym pakietem/przetwarzaniem równoległym, że to założenie jest poprawne.

Czy można bezpiecznie założyć, że mclapply zawsze zwraca wyniki w kolejności, niezależnie od opcjonalnych argumentów, które są podane?

+1

Docs nie wskazują, że wynik może przyjść jajecznica, i to jest jednoznaczne, że jest to równoległe wersja 'lapply', która zwraca listę uporządkowaną jako dane wejściowe. Można uruchomić część kodu w trybie sekwencyjnym i równoległym i sprawdzić, czy ma to zastosowanie w konkretnym przypadku. Zaryzykowałbym przypuszczenie, że tak. –

Odpowiedz

15

Krótka odpowiedź: wyniki są zwracane we właściwej kolejności.

Ale oczywiście, należy odczytać kod samodzielnie (mclapply jest funkcją R ...)

Strona man dla collect daje jeszcze kilka podpowiedzi:

Uwaga: Jeśli wyrażenie korzysta niski -równoległe funkcje wielordzeniowe, takie jak sendMaster, jedno zlecenie może dostarczać wyniki wielokrotnie i to na użytkowniku spoczywa odpowiedzialność za ich prawidłową interpretację.

Jednakże, jeśli nie bałagan z niskiego poziomu,

zbierać zyski żadnych wyników, które są dostępne na liście. Wyniki będą miały tę samą kolejność, co określone zadania. Jeśli istnieje wiele zadań, a zadanie ma nazwę, zostanie użyte do nadania nazwy wynikowi, w przeciwnym razie zostanie użyty jego identyfikator procesu.

(podkreślenie moje)

Teraz mclapply. Szybkie Glanc nad wydajnością kodu źródłowego:

  • jeśli !mc.preschedule i nie ma więcej miejsc pracy niż stosowane są rdzenie (length (X) <= cores) parallel i collect, patrz wyżej.
  • jeśli mc.preschedule lub więcej zleceń niż rdzenie, samo zamówienie zajmuje się mclapply - patrz kod.

Jednak tutaj jest nieco zmodyfikowana wersja eksperymentu:

> unlist (mclapply(1:10, function(x){ 
    Sys.sleep(sample(1:5, size = 1)); 
    cat (x, " ");  
    identity(x)}, 
    mc.cores = 2, mc.preschedule = FALSE)) 
1 2 4 3 6 5 7 8 9 10 [1] 1 2 3 4 5 6 7 8 9 10 
> unlist (mclapply(1:10, function(x){ 
    Sys.sleep(sample(1:5, size = 1)); 
    cat (x, " ");  
    identity(x)}, 
    mc.cores = 2, mc.preschedule = TRUE)) 
1 3 2 5 4 6 7 8 10 9 [1] 1 2 3 4 5 6 7 8 9 10 

który pokazuje, że wyniki są zwracane w innej kolejności przez pracy dzieci (dokładniej: Praca dziecko zamiar zakończyć w różny zamówienie), ale wynik jest złożony w oryginalnej kolejności.

(działa na konsoli, ale nie w RStudio - te cat s nie pokazują się tam)