mclapply возвращает NULL случайным образом
Когда я использую mclapply, время от времени (действительно случайно) это дает неверные результаты. Эта проблема довольно подробно описана в других публикациях в Интернете, например ( http://r.789695.n4.nabble.com/Bug-in-mclapply-td4652743.html). Тем не менее, решение не предусмотрено. Кто-нибудь знает, как решить эту проблему? Спасибо!
2 ответа
Проблема, о которой сообщает Уинстон Чанг, которую вы цитируете, по-видимому, была исправлена в R 2.15.3. Была ошибка в mccollect
это произошло при назначении рабочих результатов в список результатов:
if (is.raw(r)) res[[which(pid == pids)]] <- unserialize(r)
Это не удастся, если unserialize(r)
возвращает значение NULL, поскольку назначение NULL списку таким образом удаляет соответствующий элемент списка. Это было изменено в R 2.15.3 на:
if (is.raw(r)) # unserialize(r) might be null
res[which(pid == pids)] <- list(unserialize(r))
что является безопасным способом присвоения неизвестного значения списку.
Поэтому, если вы используете R <= 2.15.2, решение состоит в том, чтобы перейти на R >= 2.15.3. Если у вас есть проблема с использованием R >= 2.15.3, то, вероятно, это другая проблема, чем та, о которой сообщил Уинстон Чанг.
Я также перечитал вопросы, обсуждаемые в ветке R-help, созданной Элизабет Пурдом. Без конкретного тестового примера, я предполагаю, что проблема не в ошибке mclapply, потому что я могу воспроизвести те же симптомы с помощью следующей функции:
work <- function(i, poison) {
if (i == poison) quit(save='no')
i
}
Если работник, запущенный mclapply, умирает во время выполнения задачи по любой причине (получение сигнала, ошибка сегмента, выход), mclapply вернет NULL для всех задач, которые были назначены этому работнику:
> library(parallel)
> mclapply(1:4, work, 3, mc.cores=2)
[[1]]
NULL
[[2]]
[1] 2
[[3]]
NULL
[[4]]
[1] 4
В этом случае значения NULL были возвращены для задач 1 и 3 из-за предварительного планирования, даже если только задача 3 фактически не выполнена.
Если работник умирает при использовании такой функции, как parLapply или clusterApply, сообщается об ошибке:
> cl <- makePSOCKcluster(3)
> parLapply(cl, 1:4, work, 3)
Error in unserialize(node$con) : error reading from connection
Я видел много таких отчетов, и я думаю, что они, как правило, происходят в больших программах, которые используют множество пакетов, которые трудно превратить в воспроизводимые тестовые случаи.
Конечно, в этом примере вы также получите ошибку при использовании lapply, хотя ошибка не будет скрыта, как в случае с mclapply. Если кажется, что проблема не возникает при использовании lapply, это может быть связано с тем, что проблема возникает редко, поэтому это происходит только при очень больших запусках, которые выполняются параллельно с использованием mclapply. Но также возможно, что ошибка возникает не потому, что задачи выполняются параллельно, а потому, что они выполняются разветвленными процессами. Например, различные графические операции потерпят неудачу при выполнении в разветвленном процессе.
Я добавляю этот ответ, чтобы другим, задававшим этот вопрос, не приходилось пробираться сквозь длинную цепочку комментариев (я получатель вознаграждения, но не ОП).
mclapply
первоначально заполняет список, который он создает с NULLS. Поскольку рабочий процесс возвращает значения, эти значения перезаписывают NULLS. Если процесс умирает, никогда не возвращая значение, mclapply
вернет NULL.
Когда памяти становится мало, Linux убивает нехватку памяти (oom killer)
https://lwn.net/Articles/317814/
начнёт молча убивать процессы. Он ничего не выводит на консоль, чтобы вы знали, что он делает, хотя действия oom killer отображаются в системном журнале. В этой ситуации вывод mclapply
будет случайным образом загрязнен NULLS.