【问题标题】:How can I run a for loop in parallel in R如何在 R 中并行运行 for 循环
【发布时间】:2018-10-29 21:51:21
【问题描述】:

假设我有一个函数f() 和一个向量d

f <- function(x) dexp(x, 2)
d <- runif(10, 1, 5)

现在我想执行一个类似的 for 循环

dnew <- numeric(length(d))
for (i in seq_along(dnew)){
   dnew[i] <- f(d[i])
}

。如何并行执行此操作?

【问题讨论】:

  • “如何...并行”应该以cran.r-project.org/web/views/HighPerformanceComputing.html 开头。我认为很多人在使用 foreach 包时很幸运,其他人也觉得 future 很棒。
  • foreach 包对我没有帮助。如果我使用 foreach 会花费更多时间
  • 好的。如果正确使用foreach 没有加快速度,那么(1)启动成本不会抵消并行执行; (2) 你做错了或者可以做得更好;或 (3) 其他我们不知道的事情。一般来说,为了使并行化运行良好,计算时间必须大大超过启动成本(如果合适的话,fork R、加载库、传输数据等)。如果您包含 foreach 代码,也许精通该软件包的人可以帮助提高其性能。

标签: r parallel-processing parallel.foreach


【解决方案1】:
  • 示例代码在没有for循环的情况下更快:

    dnew2 <- f(d)          # 'f()' and 'd' from question
    all.equal(dnew, dnew2) # 'dnew' from question 
    [1] TRUE
    
    library(microbenchmark)
    microbenchmark('for loop' = for (i in seq_along(dnew)){ dnew[i] <- f(d[i]) },
                   'vectorized' = { dnew2 = f(d) })
    Unit: microseconds
           expr    min      lq     mean  median     uq    max neval
       for loop 15.639 16.4455 17.66640 17.0045 18.089 43.938   100
     vectorized  1.249  1.3140  1.44039  1.3845  1.516  2.424   100
    
  • 可以与foreach并行:

    library(foreach)
    library(doParallel); registerDoParallel(2)
    dnew3 <- foreach(i=seq_along(dnew), .combine=c) %dopar% {
        f(d[i])
    }
    all.equal(dnew, dnew3)
    [1] TRUE
    

    并行版本更慢,因为并行开销大于收益。

    microbenchmark('for loop' = for (i in seq_along(dnew)){ dnew[i] <- f(d[i]) },
                   'foreach' = { dnew3 <- foreach(i=seq_along(dnew), .combine=c) %dopar% {
                                          f(d[i]) } 
                                })
    Unit: microseconds
         expr       min        lq        mean     median         uq       max neval
     for loop    17.799    22.048    31.01027    32.7615    37.0945    67.265   100
      foreach 11875.845 13003.558 13576.64759 13427.1015 14041.3455 17782.638   100
    
  • 如果f() 需要更多时间进行评估,foreach 版本会更快:

    f <- function(x){
        Sys.sleep(.3)
        dexp(x, 2)
    }
    microbenchmark('for loop' = for (i in seq_along(dnew)){ dnew[i] <- f(d[i]) },
                   'foreach' = {dnew3 <- foreach(i=seq_along(dnew), .combine=c) %dopar% {
                                         f(d[i]) }
                    }, times=2)
    Unit: seconds
         expr      min       lq     mean   median       uq      max neval
     for loop 3.004271 3.004271 3.004554 3.004554 3.004837 3.004837     2
      foreach 1.515458 1.515458 1.515602 1.515602 1.515746 1.515746     2
    

【讨论】:

  • 你应该结合 foreach 和你的矢量化函数(在 ncores 块中分开)。
【解决方案2】:

简单的for循环

a <- function(x) {dexp(x,2)}
d<- runif(10,1,5)
d
dnew < - numeric(length(d))
for (i in 1: length(dnew)){
dnew[i]<- a(d[i])
}
dnew

并行版

library(doParallel)
dnew < - numeric(length(d))
no_cores <- detectCores() - 1  
registerDoParallel(cores=no_cores)  
cl <- makeCluster(no_cores, type="FORK")  
dnew <- clusterApply(cl=cl, x=d, fun = a)  
stopCluster(cl) 
dnew 

看看这个博客的帖子:https://www.r-bloggers.com/lets-be-faster-and-more-parallel-in-r-with-doparallel-package/

希望对你有帮助!

【讨论】:

  • 这似乎更像是评论而不是答案。作为答案,它应该至少包含对 OP 数据/代码的改编。当链接失效时,仅链接往往会过时(尽管到目前为止,r-bloggers 在长寿方面做得相当不错)。
猜你喜欢
  • 2016-11-14
  • 2013-12-12
  • 1970-01-01
  • 2016-05-27
  • 2015-09-04
  • 1970-01-01
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
相关资源
最近更新 更多