Это немного похоже на ваш другой вопрос: связь между узлами в кластере занимает больше времени, чем фактическая функция.
Это можно проиллюстрировать, изменив свои функции:
library(snow)
cl <- makeCluster(2)
SnowSim <- function(cluster, nSims=10,n){
parSapply(cluster, 1:nSims, function(x){
Sys.sleep(n)
x
})
}
library(foreach)
library(doSNOW)
registerDoSNOW(cl)
ForSim <- function(nSims=10,n) {
foreach(i=1:nSims, .combine=c) %dopar% {
Sys.sleep(n)
i
}
}
Таким образом, мы можем моделировать функцию длинного расчета и короткого вычисления в различном количестве симуляций. Давайте возьмем два случая, один из которых рассчитан на 1 секунду и 10 циклов, а другой - на 1 мс и 10000 циклов. Оба должны длиться 10 секунд:
> system.time(SnowSim(cl,10,1))
user system elapsed
0 0 5
> system.time(ForSim(10,1))
user system elapsed
0.03 0.00 5.03
> system.time(SnowSim(cl,10000,0.001))
user system elapsed
0.02 0.00 9.78
> system.time(ForSim(10000,0.001))
user system elapsed
10.04 0.00 19.81
По сути, вы видите, что для длинных вычисляющих функций и низких симуляций распараллеленные версии аккуратно сокращают время вычисления вдвое, как и ожидалось.
Теперь симуляции, которые вы делаете, относятся ко второму случаю. Там вы видите, что решение snow
на самом деле больше ничего не меняет, а решение foreach
даже требует вдвое больше. Это просто из-за накладных расходов на связь между узлами и между ними, а также на обработку возвращаемых данных. Издержки foreach
намного больше, чем с snow
, как показано в моем ответе на ваш предыдущий вопрос.
Я не запустил Ubuntu, чтобы попробовать кластер MPI, но это в основном та же история. Между различными типами кластеров существуют тонкие различия в зависимости от времени, необходимого для связи, отчасти из-за различий между базовыми пакетами.