【问题标题】:doMC in R and foreach loop not workingR和foreach循环中的doMC不起作用
【发布时间】:2012-07-21 23:34:48
【问题描述】:

我正在尝试让 foreach 包在 R 中进行并行处理,但我遇到了几个问题:

使 foreach 工作所需的 doMC 包在 CRAN for Windows 上不存在。一些博客建议 doSNOW 应该做同样的工作。但是,当我使用 doSNOW 运行 foreach 命令时,%dopar% 的运行速度似乎并不比%do% 快。事实上,它要慢得多。我的 CPU 是带有 8 GB RAM 的 Intel i7 860 @ 2.80GHz。以下是我的代码:

##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   

【问题讨论】:

  • %dopar% 示例在我的机器上运行得更快,运行 R-2.15.1、doSNOW_1.0.5、snow_0.3-8、foreach_1.3.2、codetools_0.2-8 和 iterators_1.0.5 .你机器上sessionInfo 的输出是什么?
  • 请编辑您的问题并添加该信息。它会更容易阅读。

标签: windows r foreach parallel-processing domc


【解决方案1】:

我知道这是一个较老的问题,但我在搜索其他内容时遇到了它,并认为我会添加我的解决方案。我发现将试验的总数分成单独的试验组(组的数量等于处理器内核的数量)比尝试一次并行化所有试验并处理所有开销更有效。以下是使用 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)

在运行 Ubuntu 12.04 的 3.4 GHz 四核 i7 上的执行时间:

> t1
elapsed 
   34.5 
> t2
elapsed 
   26.5 
> t3
elapsed 
  8.295 

【讨论】:

  • 谢谢 pistachionut,我正在寻找这样的东西。这个实现在linux上工作吗?我将自己测试一下。如果是这样,如果它是纯 Windows 或跨平台解决方案,您可能需要明确编写。
【解决方案2】:

你最好在 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 虚拟机上运行,​​R 2.15.1 32 位,只允许 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] 

就我而言,%do% 需要 17.6 秒,%dopar% 需要 14.8 秒。观察任务执行,似乎大部分执行时间是cbind,这是并行运行的常见问题。在我自己的模拟中,我已经完成了自定义工作,将我的详细结果保存为并行任务的一部分,而不是通过foreach 返回它们,以消除这部分开销。 YMMV。

【讨论】:

  • 成功了!!能否解释一下为什么 %dopar% 循环中的代码需要重复复制?复制代码的次数是否重要?感谢您的大力帮助!
  • 重复的代码是从@Dieter 的回答中复制而来的。也许他可以解释一下。
  • 有趣的是,小插图“doParallel 和 foreach 入门”(OP 的示例来自此)似乎淡化了并行处理的潜在收益。我学会了使用“Package:'parallel'”小插图中的mclapply 示例来构建我的并行化。无论如何,我发布了我将如何实现 OP 示例的并行运行,这会产生更快的计算。
【解决方案3】:

对于这种类型的并行来说,这并非不典型,并且可能取决于操作系统。我和你有相似的结果,但是当我对代码做了一个愚蠢的改变时

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 处理它,它的开销要低得多,但使用起来要复杂得多(我认为 Dirk 会不同意)。 (将其更改为“不那么优雅”。

【讨论】:

  • 感谢您的帮助。它可能确实取决于操作系统,因为 %dopar% 在另一个操作系统上运行得更快。再次感谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-13
  • 2021-07-26
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 2020-05-27
相关资源
最近更新 更多