Разрешить работникам foreach регистрировать и распределять подзадачи между другими работниками.

У меня есть код R, который включает несколько рабочих foreach для параллельного выполнения некоторых задач. Я использую foreach и doMC для этой цели. Я хочу, чтобы каждый из рабочих foreach набирал новых рабочих и распространял им некоторые части своего кода, который можно распараллелить.

Текущий код выглядит так:

require(doMC)
require(foreach)
registerDoMC(cores = 8)

foreach (i = (1:8)) %dopar% {
<<some code here>>
    for (j in c(1:4))  {
    <<some other code here>>
    }
}

Я ищу идеальный код, который будет выглядеть так:

require(doMC)
require(foreach)
registerDoMC(cores = 8)

foreach (i = (1:8)) %dopar% {
<<some code here>>
    foreach (j = (1:4)) %dopar% {
    <<some other code here>>
    }
}

Я видел пример мультипарадигмального параллелизма с использованием doSNOW и doMC https://www.rmetrics.org/files/Meielisalp2009/Presentations/Lewis.pdf#page=17. Однако я не знаю, делает ли он то, что я хочу, или нет.

Кроме того, кажется, что вложенный foreach неприменим, поскольку для этого требуется объединить два цикла (см. здесь), хотя в моем случае это нежелательно; второй цикл помогает первому только для части кода. Пожалуйста, поправьте меня, если я ошибаюсь.

Спасибо.


person imriss    schedule 20.06.2013    source источник
comment
Возможно, это не совсем то, что вам нужно, но вы можете иметь вложенные foreach выражения: cran.r-project.org/web/packages/foreach/vignettes/nested.pdf . Однако я не знаю о найме большего количества рабочих внутри циклов.   -  person ialm    schedule 21.06.2013
comment
Спасибо. Однако кажется, что вложенный foreach неприменим в моем случае, потому что он требует объединения двух вложенных циклов, а мне нужен внутренний цикл, который вызывается только для части кода. Я обновлю вопрос, чтобы отразить это.   -  person imriss    schedule 21.06.2013


Ответы (1)


Нет особых проблем с наличием цикла foreach внутри цикла foreach. Вот пример цикла doMC внутри цикла doSNOW:

library(doSNOW)
hosts <- c('host-1', 'host-2')
cl <- makeSOCKcluster(hosts)
registerDoSNOW(cl)
r <- foreach(i=1:4, .packages='doMC') %dopar% {
  registerDoMC(2)
  foreach(j=1:8, .combine='c') %dopar% {
    i * j
  }
}
stopCluster(cl)

Мне кажется естественным использовать doMC для внутреннего цикла, но вы можете делать это как хотите. Вы также можете использовать doSNOW для обоих циклов, но тогда вам нужно будет создать и остановить снежный кластер внутри внешнего цикла foreach.

Вот пример использования doMC внутри цикла doMC:

library(doMC)
registerDoMC(2)
r <- foreach(i=1:2, .packages='doMC') %dopar% {
  ppid <- Sys.getpid()
  registerDoMC(2)
  foreach(j=1:2) %dopar% {
    c(ppid, Sys.getpid())
  }
}

Результаты показывают, что всего шесть процессов разветвляются пакетом doMC, хотя только четыре выполняют тело внутреннего цикла:

> r
[[1]]
[[1]][[1]]
[1] 14946 14949

[[1]][[2]]
[1] 14946 14951


[[2]]
[[2]][[1]]
[1] 14947 14948

[[2]][[2]]
[1] 14947 14950

Конечно, вам нужно быть осторожным, чтобы не запускать слишком много процессов на одном узле. Я нашел этот вид вложения немного неудобным, что привело к разработке оператора вложения.

person Steve Weston    schedule 21.06.2013
comment
Спасибо. Я использую MOAB для отправки заданий, поэтому я не могу выбрать имена хостов. Есть ли наилучшая практика для установки количества узлов и процессоров в запросе MOAB, чтобы избежать сходства процессоров? Например, в первом примере выше, должен ли я запрашивать nodes=4;ppn=8? - person imriss; 24.06.2013
comment
@imriss Вы хотите использовать кластер MPI или SOCK? Если MPI, вы используете Open MPI или что-то еще? И используете ли вы Torque в качестве менеджера ресурсов с Moab? - person Steve Weston; 24.06.2013
comment
Строки сценария msub начинаются с #PBS, поэтому я думаю, что это Torque/Moab. В текущем коде я использую doMC и foreach для внешнего цикла, а внутренний цикл является последовательным. У меня нет прав администратора, но я могу устанавливать пакеты в свою домашнюю папку. Спасибо. - person imriss; 24.06.2013
comment
@imriss Да, вы должны использовать nodes=4:ppn=8, но ваш R-скрипт должен прочитать содержимое $PBS_NODEFILE, чтобы определить, как создать кластер SOCK и сколько ядер использовать во внутреннем цикле foreach. Я могу показать вам код для этого, но он не поместится в комментарий. Я предлагаю вам задать это как новый вопрос. - person Steve Weston; 24.06.2013