R doParallel foreach worker 超时错误,并且永远不会返回



以下问题是一个非常详细的问题,与此处描述的问题相关。上一个问题

使用 Ubuntu Server 14.04 LTS 64 位 Amazon 系统映像在 R 版本 3.2.3 的 c4.8xlarge(36 核)上启动。

请考虑以下代码

library(doParallel)
cl=makeCluster(35)
registerDoParallel(cl)
tryCatch({
  evalWithTimeout({
    foreach(i=1:10) %:%
      foreach(j=1:50) %dopar% {
        tryCatch({
          evalWithTimeout({
            set.seed(j)
            source(paste("file",i,".R", sep = "")) # File that takes a long time to run
            save.image(file=paste("file", i, "-run",j,".RData",sep=""))
          },
          timeout=300); ### Timeout for individual processes
        }, TimeoutException=function(ex) {
          return(paste0("Timeout 1 Fail ", i, "-run", j))
        })
      }
  },
  timeout=3600); ### Cumulative Timeout for entire process
}, TimeoutException=function(ex) {
  return("Timeout 2 Fail")
})
stopCluster(cl)

请注意,这两个超时异常都有效。我们注意到各个进程超时,如有必要,累积进程超时。

但是,我们发现单个进程可以启动,并且由于未知原因不会在 300 秒后超时。请注意,单个进程超时可确保进程不会"花费很长时间"。结果,内核被这个单一进程占用,并以 100% 的速度运行,直到达到 3600 秒的累积超时。请注意,进程及其核心将被无限期占用,如果累积超时未到位,foreach 循环将无限期地继续。达到累积时间后,将返回"超时 2 失败",脚本将继续。

问题:如果单个工作进程"挂起",以至于连单个超时机制都不起作用,如何重新启动工作进程,以便它可以继续在并行处理中使用?如果无法重新启动工作线程,是否可以以达到累积超时以外的方式停止工作线程?这样做可以确保进程不会在只有单个"错误"进程运行时长时间"等待"达到累积超时。

附加信息一个"逃跑"的过程或"绞死"的工人被抓获。查看使用 htop 的进程,它的状态是使用 100% CPU 运行。以下链接是进程的 gdb 回溯跟踪调用的屏幕截图

回溯截图

问题:回溯中是否确定了"失控"过程的原因?

我多次尝试让 evalWithTimeout 在非常相似的上下文中工作。我发现它非常成问题,特别是如果您使用的是数据库连接或全局变量。然而,对我来说效果很好的是创建一个使用setTimeLimit的表达式。要正确使用它,您必须将其和您的函数包装在一起 {} .下面是一个示例:

foreach(...) %dopar% {
  withCallingHandlers({ 
    setTimeLimit(360)
    # your function goes here, runs for 360 seconds, or fails
    }, 
    error = function(e) {
    # do stuff to capture error messages here
    }
  )
}

我使用CallingHandlers是因为堆栈跟踪非常有用,并且可以深入了解正在发生的事情。在我的错误函数中,我通常会执行一些操作来适当地捕获详细的错误消息,以便我可以查看损坏的内容和位置。

所以总结一下:

  1. setTimeLimit 通常比 evalWithTimeout 可靠得多
  2. 使用 withCallingsHandlers 为您提供了出色的错误处理选项和比 tryCatch 更详细的输出
  3. 请记住将错误消息保存在有用的位置并格式化它们,以便您可以看到真正发生的事情。

最新更新