5

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

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

考虑以下代码

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 循环将无限期继续。达到累积时间后,将返回“Timeout 2 Fail”并继续执行脚本。

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

附加信息 一名“逃跑”流程或“挂起”工人被抓获。使用 htop 查看进程,它的状态为 100% CPU 运行。以下链接是该进程的 gdb backtrace 调用的屏幕截图

回溯截图

问题:是否在回溯中确定了“失控”进程的原因?

4

1 回答 1

1

我多次尝试让 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
    }
  )
}

我使用 withCallingHandlers 是因为堆栈跟踪非常有用,并且可以深入了解正在发生的事情。在我的错误函数中,我通常会适当地捕获详细的错误消息,以便我可以查看发生了什么以及在哪里发生了问题。

所以总结一下:

  1. setTimeLimit 通常比 evalWithTimeout 可靠得多
  2. 使用 withCallingsHandlers 为您提供了出色的错误处理选项和比 tryCatch 更详细的输出
  3. 请记住将您的错误消息保存在有用的地方并格式化它们,以便您可以看到真正发生了什么。
于 2017-11-01T08:02:35.990 回答