【问题标题】:Parallel process in chunks giving no performance benefits块中的并行进程没有性能优势
【发布时间】:2017-08-03 08:41:11
【问题描述】:

我有一个非常大的列表 (huge_list)。为列表的每个值调用一个函数 (inner_fun)。 Inner_fun 大约需要 0.5 秒。inner_fun 的输出是一个大小为 3 的简单数字向量。我正在尝试并行化这种方法。看了很多文章都提到,并行功能很快的时候最好分块。所以我根据核心来划分它。但是没有时间优势。我无法理解这里的概念。任何人都可以对此提供一些见解。我主要担心的是,如果我对代码做错了什么。我没有在这里发布确切的代码。但我试图尽可能多地复制

观察很少:

  1. dummy_fun 和 dummy_fun2 大约需要 10 小时,并行保持为 11
  2. 没有并行,这大约需要 20 小时。
  3. parallel=2,15 小时内完成
  4. 我使用的是 12 核,60 GB RAM,ubuntu 机器

制作集群的代码

no_of_clusters<-detectCores()-1
cl <- makeCluster(no_of_clusters) ; registerDoParallel(cl) ; 
clusterExport(cl, varlist=c("arg1","arg2","inner_fun"))

没有块的函数

dummy_fun<-function(arg1,arg2,huge_list){
  g <- foreach (i = 1: length(huge_list),.combine=rbind,
                .multicombine=TRUE) %dopar% {
                    inner_fun(i,arg1,arg2,huge_list[i])
                }
    return(g)
}

**带有块的函数**

dummy_fun2<-function(arg1,arg2,huge_list){
  il<-1:length(huge_list)
  il2<-split(il, ceiling(seq_along(il)/(length(il)/(detectCores()-1))))
  g <- foreach ( i= il2 , .combine=rbind,.multicombine=TRUE) %dopar% {
  ab1<-lapply(i,function(li) 
           { 
            inner_fun(i,arg1,arg2,huge_list(i))
           }
          )
   do.call(rbind,ab1)
}
   return(g)
}

【问题讨论】:

  • 你应该在你的(串行)函数上尝试profvis来检查你需要改进的部分
  • 我不明白您为什么将 15 小时而不是 20 小时视为“没有时间收益”。您应该期望 K 核的性能(就等待时间而言)提高 K 倍,仅针对完全可并行化的问题,这是现实世界问题的一个非常狭窄的范围。
  • 您能否提供类似于huge_listinner_fun 的内容? huge_list 的大小(在内存中)是多少? inner_fun 可以矢量化吗?
  • 很抱歉没有让我的问题陈述变得清晰。我们已经优化了 inner_fun 中所有可能的选项。如前所述,我的目的是了解为什么块表现不佳。假设列表有大约 10000 个对象。如果如果 1 个对象需要 n 秒。如果我通过在 for 循环 * 10(times parallel) 中计算 1000 个对象来细分任务。时间应该远小于当前基准

标签: r parallel-processing doparallel


【解决方案1】:

你弄错了块。这不是将索引划分为长度为no_of_clusters 的块,而是将它们划分为no_of_clusters 块。

试试这个:

dummy_fun2 <- function(arg1, arg2, huge_list, inner_fun, ncores) {

  cl <- parallel::makeCluster(ncores)
  doParallel::registerDoParallel(cl)
  on.exit(parallel::stopCluster(cl), add = TRUE)

  L <- length(huge_list)
  inds <- split(seq_len(L), sort(rep_len(seq_len(NCORES), L)))

  foreach(l = seq_along(inds), .combine = rbind) %dopar% {
    ab1 <- lapply(inds[[l]], function(i) {
      inner_fun(i, arg1, arg2, huge_list[i])
    })
    do.call(rbind, ab1)
  }
}

补充说明:

  1. 使用计算机上一半以上的内核通常是没有用的。

  2. .multicombine 选项自动与rbind 一起使用。但是.maxcombine 真的很重要(需要超过 100 个)。在这里,我们使用lapply 作为顺序部分,所以这句话无关紧要。

  3. 使用foreach的时候多导出也没用,已经从dummy_fun2的环境中导出了需要的东西。

  4. 您确定要使用huge_list[i](获取一个元素的列表)而不是huge_list[[i]](获取列表的第i个元素)吗?

【讨论】:

  • 不错的答案,但我很好奇你为什么说it's often useless to use more than half of the cores?在我看来,这似乎太笼统了
  • 非常感谢 F. Privé。原始代码具有您提到的块大小。在这里写的时候,我弄错了。不管怎样,我编辑了它,谢谢你注意到它。除了大块之外,其余的 cmets 都没有尝试过。一两天后我会尽快更新结果。
  • @ChiPak 我在几个应用程序和配置方面的经验。如果你有反例,我想知道:-)
  • @FPrive 我认为如果您的迭代/工作者不需要 super 很长时间,但如果每次迭代都需要 super根据我的经验,很长一段时间,foreach 将使用尽可能多的内核。
  • 举个例子,我就信服了! :')
猜你喜欢
  • 1970-01-01
  • 2015-01-06
  • 2015-04-12
  • 2011-12-18
  • 1970-01-01
  • 2010-10-20
  • 2011-03-21
  • 2010-09-12
  • 1970-01-01
相关资源
最近更新 更多