R并行编程:如何终止无对应对象的集群?
问题:函数崩溃后如何终止遗留的parallel集群?
我正在开发一个以parallel::makeCluster()启动、parallel::stopCluster()收尾的函数。有时函数会中途崩溃,导致集群无法正常终止。
演示代码:
library('doParallel') show_problem <- function(n.cores=7) { clust <- makeCluster(n.cores,type='FORK') registerDoParallel(cl = clust) stop('Here is an error message, the function will stop before it gets to the next line.') stopCluster(cl = clust) } show_problem() showConnections(all=T)
函数崩溃后,showConnections(all=T)会显示工作节点的"sockconn"连接仍处于开放状态,工作线程也在持续运行。但由于clust对象仅存在于show_problem()函数的作用域内,函数结束后无法调用stopCluster()来终止集群。
请问是否有办法从函数外部找到或重建clust对象的相关信息,从而执行stopCluster()?
我已了解可使用on.exit()预防该问题,但仍好奇:若问题已发生,是否有事后补救的方法?
事后补救方案
方法1:通过系统进程直接终止工作线程
使用type='FORK'时,工作线程是当前R进程的子进程,可通过系统命令定位并杀死:
- 获取当前R主进程PID:
main_pid <- Sys.getpid()
- 按操作系统执行对应命令:
- Linux/macOS:
# 筛选主进程的子进程PID child_pids <- system(sprintf("ps -o pid= --ppid %d", main_pid), intern = TRUE) # 强制终止所有子进程 if (length(child_pids) > 0) { system(sprintf("kill -9 %s", paste(child_pids, collapse = " "))) } - Windows:Windows不支持FORK模式(默认用PSOCK),可通过以下命令处理:
# 获取子进程PID child_pids <- system(sprintf("tasklist /FI \"PPID eq %d\" /FO CSV /NH", main_pid), intern = TRUE) child_pids <- gsub('"', '', sapply(strsplit(child_pids, ","), `[`, 1)) # 强制终止子进程 if (length(child_pids) > 0 && child_pids != "") { system(sprintf("taskkill /PID %s /F", paste(child_pids, collapse = " "))) }
- Linux/macOS:
方法2:重建PSOCK集群对象(仅适用于PSOCK模式)
如果使用的是PSOCK集群(Windows默认或指定type='PSOCK'),可通过端口信息重建集群后终止:
- 执行
showConnections(all=T)查看开放的sockconn连接,记录集群对应的端口号。 - 手动创建集群对象并终止:
# 假设端口为12345,节点数为7 clust <- parallel::makePSOCKcluster(rep("localhost", 7), port = 12345) parallel::stopCluster(clust)
注:FORK模式下无法通过此方法重建集群,推荐使用方法1。
补充说明
事后补救虽可行,但on.exit(parallel::stopCluster(clust), add = TRUE)仍是最可靠的预防手段,能确保函数无论正常结束还是崩溃,集群都会被自动终止。
内容的提问来源于stack exchange,提问作者bluemouse
相关产品推荐
相关产品推荐

