R параллельные вычисления и зомби-процессы

По сути, это продолжение этот более специализированный вопрос. Было несколько сообщений о создании зомби-процессов при выполнении параллельных вычислений в R:

  1. Как запретить R оставлять зомби-процессы позади
  2. Как убить рабочего doMC, когда это будет сделано?
  3. Удалить процессы-зомби с помощью параллельного пакета

Существует несколько способов выполнения параллельных вычислений, и я сосредоточусь на трех способах, которые я использовал до сих пор на локальной машине. Я использовал doMC и doParallel с пакетом foreachна локальном компьютере с 4ядрами:

(a) Регистрация форк-кластера:

library(doParallel)
cl <- makeForkCluster(4)
# equivalently here: cl <- makeForkCluster(nnodes=getOption("mc.cores", 4L))
registerDoParallel(cl)
    out <- foreach(i=1:1000, .combine = "c") %dopar% {
        print(i)
    }
stopCluster(cl)

(b) Регистрация кластера PSOCK:

library(doParallel)
cl <- makePSOCKcluster(4)
registerDoParallel(cl)
    out <- foreach(i=1:1000, .combine = "c") %dopar% {
        print(i)
    }
stopCluster(cl)

(в) Использование doMC

library(doMC)
library(doParallel)
registerDoMC(4)
    out <- foreach(i=1:1000, .combine = "c") %dopar% {
        print(i)
    }

Несколько пользователей заметили, что при использовании метода doMC, который является просто оболочкой для функции mclapply, поэтому это не ошибка doMCs (см. здесь: Как убить doMC worker, когда он закончит работу?) -- оставляет зомби-процессы позади. В ответе на предыдущий вопрос (Как остановить R от выхода зомби-процессы позади) было высказано предположение, что использование разветвленного кластера может не оставить зомби-процессы позади. В другом вопросе было предложено (удалить зомби-процессы с помощью параллельного пакета), используя кластер PSOCK может не оставить процессы-зомби позади. Однако кажется, что все три метода обходят зомби-процесс. Хотя зомби-процессы сами по себе обычно не представляют проблемы, поскольку они (обычно) не связывают ресурсы, они загромождают дерево процессов. Тем не менее, я мог бы избавиться от них, закрыв и снова открыв R, но это не лучший вариант, когда я нахожусь в середине сеанса. Есть ли объяснение, почему это происходит (или даже: есть ли причина, по которой это должно происходить)? И можно ли что-то сделать, чтобы не осталось зомби-процессов?

Информация о моей системе (R используется в простом сеансе repl с xterm и tmux):

library(devtools)
> session_info()
Session info-------------------------------------------------------------------
 setting  value                                             
 version  R Under development (unstable) (2014-08-16 r66404)
 system   x86_64, linux-gnu                                 
 ui       X11                                               
 language (EN)                                              
 collate  en_IE.UTF-8                                       
 tz       <NA>                                              

Packages-----------------------------------------------------------------------
 package    * version  source          
 codetools    0.2.8    CRAN (R 3.2.0)  
 devtools   * 1.5.0.99 Github (c429ae2)
 digest       0.6.4    CRAN (R 3.2.0)  
 doMC       * 1.3.3    CRAN (R 3.2.0)  
 evaluate     0.5.5    CRAN (R 3.2.0)  
 foreach    * 1.4.2    CRAN (R 3.2.0)  
 httr         0.4      CRAN (R 3.2.0)  
 iterators  * 1.0.7    CRAN (R 3.2.0)  
 memoise      0.2.1    CRAN (R 3.2.0)  
 RCurl        1.95.4.3 CRAN (R 3.2.0)  
 rstudioapi   0.1      CRAN (R 3.2.0)  
 stringr      0.6.2    CRAN (R 3.2.0)  
 whisker      0.3.2    CRAN (R 3.2.0)  

Небольшое редактирование: по крайней мере, для makeForkCluster() кажется, что иногда вилки, которые он порождает, убиваются и пожинаются родителем правильно, а иногда они не пожинаются и становятся зомби. Кажется, это происходит только тогда, когда кластер закрывается недостаточно быстро после прерывания или завершения цикла; по крайней мере, так было в последние несколько раз.


person lord.garbage    schedule 19.08.2014    source источник


Ответы (1)


Вы можете избавиться от зомби-процессов, используя встроенный пакет. Просто реализуйте функцию, которая вызывает «waitpid»:

library(inline)
includes <- '#include <sys/wait.h>'
code <- 'int wstat; while (waitpid(-1, &wstat, WNOHANG) > 0) {};'
wait <- cfunction(body=code, includes=includes, convention='.C')

Я проверил это, сначала создав несколько зомби с помощью функции mclapply:

> library(parallel)
> pids <- unlist(mclapply(1:4, function(i) Sys.getpid(), mc.cores=4))
> system(paste0('ps --pid=', paste(pids, collapse=',')))
  PID TTY          TIME CMD
17447 pts/4    00:00:00 R <defunct>
17448 pts/4    00:00:00 R <defunct>
17449 pts/4    00:00:00 R <defunct>
17450 pts/4    00:00:00 R <defunct>

(Обратите внимание, что я использую GNU-версию «ps», которая поддерживает опцию «--pid».)

Затем я вызвал свою функцию «ожидания» и снова вызвал «ps», чтобы убедиться, что зомби ушли:

> wait()
list()
> system(paste0('ps --pid=', paste(pids, collapse=',')))
  PID TTY          TIME CMD

Похоже, что рабочие процессы, созданные mclapply, исчезли. Это должно работать до тех пор, пока процессы были созданы текущим процессом R.

person Steve Weston    schedule 19.08.2014
comment
Спасибо за это ... спасение жизни - person Carl Boneri; 02.03.2017