这基本上是对this更专业化问题的跟进。在R
中进行并行计算时,有一些关于创建僵尸进程的帖子:
有几种方法可以进行并行计算,我将重点介绍目前在本地计算机上使用的三种方法。我在doMC
内核的本地计算机上使用doParallel
和foreach
4
包:
(a)注册一个fork集群:
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)
(c)使用doMC
library(doMC)
library(doParallel)
registerDoMC(4)
out <- foreach(i=1:1000, .combine = "c") %dopar% {
print(i)
}
有几个用户观察到使用doMC
方法时 - 它只是mclapply
函数的包装器,因此它不是doMC
的错误(请参阅此处:{{3} }) - 留下僵尸进程。在对上一个问题(How to kill a doMC worker when it's done?)的回答中,有人建议使用fork集群可能不会留下僵尸进程。在另一个问题中,有人建议(How to stop R from leaving zombie processes behind)使用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()
,似乎有时它产生的叉子会被父母正确杀死和收获,有时它们不会被收割并成为僵尸。似乎只有在循环中止或完成后群集没有足够快地关闭时才会发生这种情况;至少那是在最后几次发生的时候。
答案 0 :(得分:16)
你可以使用&#34; inline&#34;摆脱僵尸进程。包。只需实现一个调用&#34; waitpid&#34;:
的函数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版本的&#34; ps&#34;它支持&#34; - pid&#34;选项。)
然后我打电话给我&#34;等待&#34;功能和称为&#34; ps&#34;再次验证僵尸已经消失:
> wait()
list()
> system(paste0('ps --pid=', paste(pids, collapse=',')))
PID TTY TIME CMD
看来mclapply创建的工作进程现在已经消失了。只要流程是由当前的R流程创建的,这就应该有效。