2016-11-24 44 views
5

Mam proces, który chcę wykonać równolegle, ale nie udało mi się z powodu jakiegoś strange error. Teraz rozważam połączenie i obliczyć nieudane zadanie na głównym procesorze. Jednak nie wiem, jak napisać taką funkcję dla .combine.Budowanie funkcji dla domeny .com w foreach

Jak należy to zapisać?

Wiem, jak je napisać, na przykład odpowiedź this stanowi przykład, ale nie zapewnia sposobu radzenia sobie z nieudanymi zadaniami, ani powtarzania zadania na wzorzec.

chciałbym zrobić coś takiego:

foreach(i=1:100, .combine = function(x, y){tryCatch(?)} %dopar% { 
    long_process_which_fails_randomly(i) 
} 

Jednak, jak mogę używać wejścia tego zadania w funkcji .combine (jeśli można to zrobić)? Czy powinienem podać wewnątrz %dopar%, aby zwrócić flagę lub listę, aby to obliczyć?

Odpowiedz

2

Aby wykonywać zadania w funkcji łączenia, należy dołączyć dodatkowe informacje do obiektu wynikowego zwracanego przez treść pętli foreach. W takim przypadku byłaby to flaga błędu i wartość i. Istnieje wiele sposobów, aby to zrobić, ale oto przykład:

comb <- function(results, x) { 
    i <- x$i 
    result <- x$result 
    if (x$error) { 
    cat(sprintf('master computing failed task %d\n', i)) 
    # Could call function repeatedly until it succeeds, 
    # but that could hang the master 
    result <- try(fails_randomly(i)) 
    } 
    results[i] <- list(result) # guard against a NULL result 
    results 
} 

r <- foreach(i=1:100, .combine='comb', 
      .init=vector('list', 100)) %dopar% { 
    tryCatch({ 
    list(error=FALSE, i=i, result=fails_randomly(i)) 
    }, 
    error=function(e) { 
    list(error=TRUE, i=i, result=e) 
    }) 
} 

byłbym skłonny do czynienia z tym problemem poprzez wykonanie pętli równoległej, dopóki wszystkie zadania zostały wyliczone:

x <- rnorm(100) 
results <- lapply(x, function(i) simpleError('')) 

# Might want to put a limit on the number of retries 
repeat { 
    ix <- which(sapply(results, function(x) inherits(x, 'error'))) 
    if (length(ix) == 0) 
    break 

    cat(sprintf('computing tasks %s\n', paste(ix, collapse=','))) 
    r <- foreach(i=x[ix], .errorhandling='pass') %dopar% { 
    fails_randomly(i) 
    } 

    results[ix] <- r 
} 

Należy zauważyć, że to rozwiązanie korzysta z opcji .errorhandling, która jest bardzo przydatna w przypadku wystąpienia błędów. Więcej informacji na temat tej opcji można znaleźć na stronie man foreach.

+0

Dzięki za odpowiedź! Czy mógłbyś wyjaśnić, dlaczego masz ochotę powtórzyć równoległą pętlę, dopóki całe zadanie nie zostanie obliczone? Czy myślisz, że byłoby łatwiej/szybciej w ten sposób, ponieważ za każdym razem błąd występuje w innej iteracji? – Llopis

+0

@Llopis Wszystko zależy od konkretnego problemu. Jeśli błąd nie może wystąpić na kapitanie, twoje podejście jest prawdopodobnie lepsze. Jeśli jest tak samo prawdopodobne, że stanie się to na mistrzu, równie dobrze możesz wykorzystać pracowników, ponieważ będzie to szybsze. Pisanie programów odpornych na błędy może być trudne, dlatego warto pomyśleć o różnych podejściach. –

+0

No cóż, nie rozumiem pochodzenia błędu, trudno zgadnąć, ale dzięki za dostarczenie alternatyw – Llopis

Powiązane problemy