Ошибка тайм-аута рабочего процесса R doParallel foreach и никогда не возвращается

Следующий вопрос - очень подробный вопрос, связанный с вопросом, описанным здесь. Предыдущий вопрос

Используя Ubuntu Server 14.04 LTS, 64-разрядный образ машины Amazon запущен на c4.8xlarge (36 ядер) с R версии 3.2.3.

Рассмотрим следующий код

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», и сценарий продолжается.

Вопрос: если отдельный рабочий процесс "зависает" таким образом, что даже индивидуальный механизм тайм-аута не работает, как перезапустить рабочий процесс, чтобы он мог продолжать использоваться в параллельной обработке? Если нельзя перезапустить рабочего, можно ли его остановить иначе, чем при достижении кумулятивного тайм-аута? Это гарантирует, что процесс не будет продолжаться в течение длительного периода времени, «ожидая» достижения кумулятивного тайм-аута, пока выполняется только один процесс «ошибка».

Дополнительная информация "Сбежавший" процесс или "зависший" рабочий процесс были пойманы на месте. Глядя на процесс с использованием htop, он имел статус работы со 100% ЦП. Следующая ссылка представляет собой снимок экрана с вызовом обратной трассировки gdb для процесса.

скриншот обратной трассировки

Вопрос. Идентифицирована ли причина "неуправляемого" процесса в трассировке?


person user1325068    schedule 01.03.2016    source источник
comment
В настоящее время я испытываю ту же проблему на большом вычислительном кластере, работающем под управлением R/3.2.0. Я установил исключение тайм-аута для отдельных процессов, но также обнаружил, что некоторые из них не прерываются после установленного времени, также по неизвестной причине. Любая помощь будет оценена по достоинству.   -  person qdread    schedule 20.08.2018


Ответы (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. Не забудьте сохранить сообщения об ошибках где-нибудь полезным и отформатировать их, чтобы вы могли видеть, что происходит на самом деле.
person Brandon Bertelsen    schedule 01.11.2017