DoMC в R и цикл foreach не работает
Я пытаюсь получить пакет foreach для параллельной обработки в R, работающий, и у меня есть несколько проблем:
Пакет doMC, необходимый для работы foreach, не существует в CRAN для Windows. Некоторые блоги предполагают, что doSNOW должен выполнять ту же работу. Тем не менее, когда я запускаю команду foreach с помощью doSNOW, %dopar%
похоже не работает быстрее чем %do%
, На самом деле это намного медленнее. Мой процессор - Intel i7 860 @ 2.80GHz с 8 ГБ оперативной памяти. Ниже мой код:
##Run example in 1 core
require(foreach)
require(doSNOW)
x= iris[which(iris[,5] != "setosa"),c(1,5)]
trials = 10000
system.time({
r= foreach(icount(trials), .combine=cbind) %do% {
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
# elapsed
# 37.28
# Same example in 2 cores
registerDoSNOW(makeCluster(2,type="SOCK"))
getDoParWorkers()
trials = 10000
system.time({
r= foreach(icount(trials), .combine=cbind) %dopar% {
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
# elapsed
# 108.14
Я переустановил все требуемые пакеты, но все те же проблемы. Вот вывод:
sessionInfo()
#R version 2.15.1 (2012-06-22)
#Platform: i386-pc-mingw32/i386 (32-bit)
#locale:
#[1] LC_COLLATE=English_United States.1252
#[2] LC_CTYPE=English_United States.1252
#[3] LC_MONETARY=English_United States.1252
#[4] LC_NUMERIC=C
#[5] LC_TIME=English_United States.1252
#attached base packages:
#[1] parallel stats graphics grDevices datasets utils methods
#[8] base
#other attached packages:
#[1] doParallel_1.0.1 codetools_0.2-8 doSNOW_1.0.6 snow_0.3-10
#[5] iterators_1.0.6 foreach_1.4.0 rcom_2.2-5 rscproxy_2.0-5
#loaded via a namespace (and not attached):
#[1] compiler_2.15.1 tools_2.15.1
3 ответа
Вам лучше использовать в Windows doParallel()
:
require(foreach)
require(doParallel)
cl <- makeCluster(6) #use 6 cores, ie for an 8-core machine
registerDoParallel(cl)
Затем запустите foreach() %dopar% {}
РЕДАКТИРОВАТЬ: OP упомянул все еще видя проблему, поэтому включая мой точный код Работает на 4-ядерной Windows7 VM, R 2.15.1 32-bit, только doParallel
использовать 3 моих ядра:
require(foreach)
require(doParallel)
cl <- makeCluster(3)
registerDoParallel(cl)
x= iris[which(iris[,5] != "setosa"),c(1,5)]
trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %do%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]
system.time(
foreach(icount(trials), .combine=cbind) %dopar%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]
В моем случае я получаю 17,6 сек %do%
и 14,8 сек для %dopar%
, Наблюдая за выполнением задач, кажется, что большая часть времени выполнения cbind
, который является распространенной проблемой, работающей параллельно. В моем собственном моделировании я выполнил пользовательскую работу, чтобы сохранить свои подробные результаты как часть параллельной задачи, а не возвращать их через foreach
, чтобы удалить эту часть накладных расходов. YMMV.
Я знаю, что это старый вопрос, но я наткнулся на него, когда искал что-то еще, и подумал, что добавлю свое решение. Я считаю более эффективным разделить общее количество испытаний на отдельные группы испытаний (количество групп равно числу ядер процессора), а не пытаться распараллелить все испытания одновременно и справиться со всеми накладными расходами. Вот сравнение с использованием примера OP:
require(doParallel)
x <- iris[which(iris[,5] != "setosa"),c(1,5)]
trials <- 10000
# example using a single core
t1 <- system.time({
r1 <- foreach(icount(trials), .combine=cbind) %do% {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
# example using 4 cores and parallelizing each model trial
nCores <- 4
cl <- makeCluster(nCores)
registerDoParallel(cl)
t2 <- system.time({
r2 <- foreach(icount(trials), .combine=cbind) %dopar% {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
# example using 4 cores and parallelizing a group of trial runs
trialsPerCore <- as.integer(ceiling(trials / nCores)) # number of trials
# do to on each core
# function to do a single model run
model <- function(x) {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
# function producing a group of model runs
modelRun <- function(trials, x) {
replicate(trials, model(x))
}
# call the model run for each core
t3 <- system.time(
r3 <- foreach(icount(nCores), .combine= cbind) %dopar% modelRun(trialsPerCore, x)
)[3]
stopCluster(cl)
Время выполнения на четырехъядерном i7 с частотой 3,4 ГГц под управлением Ubuntu 12.04:
> t1
elapsed
34.5
> t2
elapsed
26.5
> t3
elapsed
8.295
Это не является нетипичным для этого типа параллелизма и может зависеть от операционной системы. У меня был такой же результат, как и у вас, но когда я сделал глупое изменение в коде
require(foreach)
require(doSNOW)
x= iris[which(iris[,5] != "setosa"),c(1,5)]
trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %do%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]
registerDoSNOW( makeCluster(2,type="SOCK"))
getDoParWorkers()
trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %dopar%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]
чтобы имитировать тяжелую работу в foreach, я получил безубыточность для обоих. Это цена накладных расходов. Недавно у меня был похожий случай, и я обработал его напрямую с помощью MPI, который имеет гораздо меньшие накладные расходы, но гораздо более сложен в использовании (Дирк, я полагаю, не согласится). (Измените это на "гораздо менее элегантный".