Разрешить каждому работнику регистрироваться и распространять подзадачи другим работникам
У меня есть 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
Конечно, вы должны быть осторожны, чтобы не запускать слишком много процессов на одном узле. Я обнаружил, что этот тип вложений немного неловкий, что привело к развитию оператора вложенности.