Параллельный снегопад R, Rscript.exe становится неактивным один за другим со временем

Я использую sfApply в пакете R snowfall для параллельных вычислений. Нужно запустить 32000 тестов. Код работает нормально при запуске вычислений, он создает 46 процессов Rscript.exe, и каждый Rscript.exe использует 2% загрузки процессора. Общее использование процессора составляет около 100%, и результаты постоянно записываются на диск. Вычисления обычно занимают десятки часов. Странно то, что процесс Rscript.exe постепенно становится неактивным (использование процессора = 0) один за другим, и соответствующий процессор тоже неактивен. Через два дня остается только половина Rscript.exe, которые активны, если смотреть на использование ЦП, а общее использование ЦП снижается до 50%. Однако до завершения работы еще далеко. Со временем все больше и больше Rscript.exe переходят в неактивное состояние, из-за чего работа длится очень и очень долго. Мне интересно, что делает процесс и ядра процессора неактивными?

Мой компьютер имеет 46 логических ядер. Я использую R-3.4.0 от Rstudio в 64-битных окнах 7. Следующая «тестовая» переменная - это матрица 32000 * 2. myfunction решает несколько дифференциальных уравнений.

Спасибо.

    library(snowfall)
    sfInit(parallel=TRUE, cpus=46)
    Sys.time()
    sfLibrary(deSolve)
    sfExport("myfunction","test")
    res<-sfApply(test,1,function(x){myfunction(x[1],x[2])})
    sfStop()
    Sys.time()

person yan    schedule 16.06.2017    source источник
comment
А как насчет использования памяти? Достаточно ли оперативной памяти? Здесь не так много, но вы можете попробовать запустить только несколько задач за раз и посмотреть, пройдут ли они. Начните увеличивать количество задач, пока не столкнетесь с узким местом.   -  person Roman Luštrik    schedule 16.06.2017
comment
Спасибо. Оперативная память доступна, используется только 10G (всего 64G). Я мог бы попробовать это, но проблема в том, что процессы постепенно неактивны. Задачи продолжаются, просто с меньшим количеством процессоров. Как будто что-то во время вычислений заставляет ядра спать одно за другим.   -  person yan    schedule 16.06.2017
comment
Извините, у меня закончились идеи. Возможно, вы могли бы использовать другой параллельный инструмент, например parallel или foreach?   -  person Roman Luštrik    schedule 16.06.2017
comment
Некоторые ошибки могут убить ядро. Кроме того, вы должны убедиться, что каждая итерация действительно завершается за разумное время. У меня часто есть данные, которые изначально кажутся сбалансированными, но операции с данными на самом деле очень несбалансированные.   -  person CPak    schedule 17.06.2017
comment
Спасибо. Именно так, как вы упомянули. После некоторого копания это должно быть из-за несбалансированного времени, необходимого для каждой работы. У меня есть задания, которые занимают больше времени в более поздней части очереди задач. Я думаю, что sfApply сначала разбивает задачи по номеру процессора по порядку и назначает задачи каждому процессору, что приводит к несбалансированному времени завершения для каждого процессора. Мое решение использует вместо этого mclapply в Linux, потому что mclapply, похоже, не поддерживает разветвление в Windows. Он имеет случайное назначение или динамическое назначение, что ускорит мои вычисления. Спасибо еще раз.   -  person yan    schedule 17.06.2017


Ответы (1)


То, что вы описываете, звучит разумно, поскольку snowfall::sfApply() использует snow::parApply() для внутреннего использования, который разбивает ваши данные (test) на (здесь) 46 фрагментов и отправляет каждый фрагмент одному из 46 рабочих процессов R. Когда рабочий процесс завершает работу над своим фрагментом, для него больше нет работы, и он просто будет бездействовать, пока оставшиеся фрагменты обрабатываются другими рабочими процессами.

Что вы хотите сделать, так это разделить ваши данные на более мелкие фрагменты, что приведет к тому, что каждый работник будет обрабатывать в среднем более одного фрагмента. Я не знаю, возможно ли (думаю?) это при снегопаде. Пакет parallel, который является частью самого R и заменяет пакет snow (на который опирается снегопад), предоставляет parApply() и parApplyLB(), где последний разбивает ваши фрагменты на минимальные размеры, то есть по одному на элемент данных (из test). Подробнее см. help("parApply", package = "parallel").

Пакет future (я автор) предоставляет возможность масштабирования насколько вы хотите разделить данные. Он предоставляет не версию apply(), а версию lapply(), которую вы можете использовать (и то, как parApply() работает внутри). Например, ваш пример, который использует один блок на каждого работника, будет таким:

library("future")
plan(multisession, workers = 46L)

## Coerce matrix into list with one element per matrix row
test_rows <- lapply(seq_len(nrow(test)), FUN = function(row) test[row,])

res <- future_lapply(test_rows, FUN = function(x) { 
  myfunction(x[1],x[2])
})

который по умолчанию

res <- future_lapply(test_rows, FUN = function(x) { 
  myfunction(x[1],x[2])
}, future.scheduling = 1.0)

Если вы хотите разделить данные так, чтобы каждый рабочий процесс обрабатывал одну строку за раз (см. parallel::parApplyLB()), вы делаете это следующим образом:

res <- future_lapply(test_rows, FUN = function(x) { 
  myfunction(x[1],x[2])
}, future.scheduling = Inf)

Установив future.scheduling в [1, Inf], вы можете контролировать, насколько велик средний размер фрагмента. Например, у future.scheduling = 2.0 каждый рабочий процесс будет обрабатывать в среднем два фрагмента данных, прежде чем future_lapply() вернется.

person HenrikB    schedule 24.06.2017