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

У меня есть 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. Однако я не знаю, делает ли он то, что хочу, или нет.

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

Благодарю.

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

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

Другие вопросы по тегам