Мне кажется, что это связано с тем, что parSapply занял целые ядра, поэтому у foreach нет дополнительных ядер для вычислений. Есть ли хорошая идея, чтобы это исправить? По сути, я хочу, чтобы оба процесса работали в параллельных версиях.
Нет, это не очень хорошая идея. В основном вы пытаетесь перепараллелизовать здесь (но это действительно происходит в вашем коде, как описано ниже).
Другая проблема: предположим, что мы можем выбрать только один процесс для параллельных вычислений, какой из них выбрать? Для семьи oop или подать заявку?
На этот вопрос нет единственно правильного ответа. Я рекомендую вам профилировать свой код *** process ***
, чтобы выяснить, насколько он выигрывает от распараллеливания.
Итак, я нашел ваш parSapply(cl, ...)
сверху foreach() %dopar% { ... }
с использованием того же кластера cl
интересным. Первый раз, когда я увидел это, спросил / предложил таким образом. Вы не хотите делать это наверняка, но вопрос / попытка не сумасшедшая. Ваша интуиция о том, что все работники будут заняты, когда foreach() %dopar% { ... }
попытается использовать их, отчасти верна. Однако на самом деле происходит также то, что оператор foreach() %dopar% { ... }
оценивается в working , а не в основном сеансе R, где был определен кластер cl
. На рабочих адаптеры foreach не зарегистрированы, поэтому по умолчанию эти вызовы будут обрабатываться последовательно (== foreach::registerDoSEQ()
). Чтобы добиться вложенного распараллеливания, вам нужно было настроить и зарегистрировать кластер внутри каждого работника, например, внутри функции myfunction()
.
Как автор future framework, я ' Я хотел бы предложить вам использовать это. Это защитит вас от вышеуказанных ошибок и не будет слишком параллельным (вы можете сделать это, если вы действительно хотите это сделать). Вот как я бы переписал ваш пример кода:
library(foreach) ## foreach() and %dopar%
myfunction <- function{data} {
df <- foreach(i = 1:200, .combine = "rbind") %:%
foreach(j = 1:200, .combine = "rbind") %dopar% {
*****
process
*****
}
data <- df[1,1]
return(data)
}
## Tell foreach to parallelize via the future framework
doFuture::registerDoFuture()
## Have the future framework parallelize using a cluster of
## local workers (similar to makeCluster(detectCores()))
library(future)
plan(multisession)
library(future.apply) ## future_sapply()
system.time({
mat <- t(future_sapply(list, myfuntion))
})
Теперь важно понять, что внешнее распараллеливание future_sapply()
будет работать в кластере с несколькими сеансами. Когда вы добираетесь до внутреннего распараллеливания foreach() %dopar% { ... }
, все, что видит foreach, является последовательным рабочим, так что внутренний уровень будет обрабатываться параллельно. Это то, что я имею в виду, что будущая инфраструктура автоматически защитит вас от чрезмерного распараллеливания.
Если вы хотите, чтобы внутренний слой распараллеливался на кластере с несколькими сеансами, а внешний - последовательным, вы можете установите это как:
plan(list(sequential, multisession))
Если вы действительно хотите выполнить вложенное распараллеливание, скажем, двух работников внешнего уровня и четырех работников внутреннего уровня, вы можете использовать:
plan(list(tweak(multisession, workers = 2), tweak(multisession, workers = 4))
Это будет запускать 2 * 4 = 8 параллельных процессов R одновременно.
Что более полезно, если у вас есть несколько доступных компьютеров, то вы можете использовать их для внешнего уровня, а затем использовать многосессионный кластер на каждый из них. Что-то вроде:
plan(list(tweak(cluster, workers = c("machine1", "machine2")), multisession))
Подробнее об этом можно прочитать в будущих виньетках.