Как правильно использовать пакеты doSMP и foreach? - PullRequest
2 голосов
/ 16 марта 2011

Я пытаюсь использовать пакет doSMP , который обеспечивает параллельный бэкэнд для пакета foreach.

Можете ли вы указать, что я делаю неправильно?Действительно, использование foreach таким образом значительно увеличивает время вычислений ...

#------register doSMP to be used with foreach------
library(doSMP)
w <- startWorkers(4)
registerDoSMP(w)
#--------------------------------------------------

#------A simple function------
sim <- function(a, b)
{
    return(10 * a + b)
}
avec <- 1:200
bvec <- 1:400
#-----------------------------

#------The naive method------
ptime <- system.time({
mat <- matrix(NA, nrow=length(avec), ncol=length(bvec))
for(i in 1:length(avec))
{
    for(j in 1:length(bvec))
    {
         mat[i, j] <- sim(avec[i], bvec[j])
    }
}
})[3]
ptime

elapsed 
   0.36
#----------------------------

#------Using foreach------
ptime <- system.time({
mat2 <- foreach(b=bvec, .combine="cbind") %:%
         foreach(a=avec, .combine="c") %dopar%
     {
            sim(a, b)
    }
})[3]
ptime

elapsed 
  86.98
#-------------------------

РЕДАКТИРОВАТЬ

Этот вопрос очень очень похож наэтот и был перенесен из stats.stackexchange.

Ответы [ 2 ]

4 голосов
/ 16 марта 2011

Мне лично не нравится пакет doSMP, так как он часто приводит к сбою моего R.Он разработан для сборки REvolution и почему-то не работает на моей машине.Например, ваш приведенный выше код, без изменений, просто приводит к сбою моей R.

Кроме того, кажется странным пытаться использовать распараллеленную функцию внутри функции цикла. Более логично выполнять распараллеливание во внешнем цикле,Коммуникация, включенная во вложенные параллельные вычисления, вызывает резкое увеличение времени вычислений.Вы ничего не получаете, так как ваша функция sim невероятно быстра.Фактически, сохранение сериализации внутреннего цикла имеет больше смысла, так как в этой ситуации время вычисления на одном ядре становится больше, чем издержки из-за связи.

Иллюстрация с использованием пакета snowfall-package и использованием вместо этого применения apply for loopingиз для петель.Это также очень наивно, так как с векторизацией можно многое выиграть (см. Ниже).

library(snowfall)
sfInit(parallel=T,cpus=2)
#same avec, bvec, sim

system.time({
    out <- sapply(avec,function(i) {
      sapply(bvec,function(j){
        sim(i,j)
      })
    })
})[3]
elapsed 
   0.33 

sfExport("avec","bvec","sim")
system.time({
    out <- sfSapply(avec,function(i) { # this one is parallel
      sapply(bvec,function(j){ # this one is not, no sense in doing so
        sim(i,j)
      })
    })
})[3]
elapsed 
   0.17 

Обе матрицы равны, кроме имен измерений из-за структуры:

> all.equal(out1,out2)
[1] "Attributes: < Length mismatch: comparison on first 1 components >"

Правильный способ R сделать это будет:

system.time(
  out3 <- outer(avec*10,bvec,"+")
)[3]
elapsed 
   0.01 

, что значительно быстрее и создаст идентичную (хотя и транспонированную) матрицу:

> all.equal(out1,t(out3))
[1] TRUE

(в качестве ссылки,ваш двойной цикл for работает на моей системе 0,73 прошедшего времени ...)

0 голосов
/ 16 марта 2011

Джорис Мейс дал мне хороший ответ здесь , который также имеет место в этой ситуации. Извините за "двойной пост"

...