r%dopar%嵌套循环不并行运行

问题描述 投票:1回答:1

我正在使用%dopar%运行嵌套循环来生成用于体验目的的虚拟数据集。参考链接:R nested foreach %dopar% in outer loop and %do% in inner loop

sample dataset

set.seed(123)
n = 10000 #number of unique IDs (10k as trial) , real data consits of 50k unique IDs
ID <- paste(LETTERS[1:8],sample(n),sep = "")
year <- c('2015','2016','2017','2018')
month <- c('1','2','3','4','5','6','7','8','9','10','11','12')

预定义的库

library(foreach)  
library(data.table)
library(doParallel)

# parallel processing setting
cl <- makeCluster(detectCores() - 1)
registerDoParallel(cl)

测试1:%dopar%脚本

system.time(
  output_table <- foreach(i = seq_along(ID), .combine=rbind, .packages="data.table") %:%
    foreach(j = seq_along(year), .combine=rbind, .packages="data.table") %:%
    foreach(k = seq_along(month), .combine=rbind, .packages="data.table") %dopar% {

    data.table::data.table(
      mbr_code = ID[i],
      year = year[j],
      month = month[k]
    )
  }
)
stopCluster(cl)

#---------#
# runtime #
#---------#
>    user  system elapsed 
> 1043.31   66.83 1171.08

测试2:%do%脚本

system.time(
  output_table <- foreach(i = seq_along(ID), .combine=rbind, .packages="data.table") %:%
    foreach(j = seq_along(year), .combine=rbind, .packages="data.table") %:%
    foreach(k = seq_along(month), .combine=rbind, .packages="data.table") %do% {

    data.table::data.table(
      mbr_code = ID[i],
      year = year[j],
      month = month[k]
    )
  }
)
stopCluster(cl)

#---------#
# runtime #
#---------#
> user  system elapsed 
> 1101.85    1.02 1110.55 

Expected output results

> view(output_table)

enter image description here

Problem

当我在%dopar%上运行时,我确实使用Resource Monitor监控我的机器的CPU性能,我注意到CPU没有得到充分利用。 enter image description here

Question

我确实尝试在我的机器i5,4核上运行上面的脚本(test1和test2)。但似乎%do%%dopar%的运行时间彼此接近。这是我的脚本设计问题?我的真实数据包括50k唯一ID,意味着如果在%do%中运行需要很长时间,我怎样才能充分利用我的机器CPU来减少运行时间?

r nested-loops doparallel parallel-foreach
1个回答
1
投票

我相信你正在看到foreach包的初始开销,因为它复制并设置了正确运行每个循环所需的一切。在运行代码大约30-60秒后,我的cpu全部使用得太充分,直到代码最终完成。

也就是说,它没有解释为什么你的代码与%do%循环相比如此之慢。我相信,当你试图访问所有foreach循环中的数据时,这里的罪人是如何应用foreach循环的。基本上,如果你没有.export你需要的数据,它将尝试在几个并行会话中访问相同的数据,并且每个会话将必须等待其他会话完成访问他们自己的数据。通过使用foreach中的.export参数导出数据,可以减轻这种情况。我个人使用其他包来执行我的大多数平行化,所以如果这是你想要的,我建议测试一下。然而,这将带来更大的开销。

更快的方法:

现在,当您尝试创建一个虚拟数据集时,将某些列的所有组合组合在一起,有更快的方法来获取它。快速搜索“交叉加入”将lead you to posts like this one.

对于data.table包,使用'CJ'功能可以非常高效和快速地完成。只是

output <- CJ(ID, year, month)

将产生嵌套循环尝试创建的结果,仅使用大约0.07秒来执行任务。

© www.soinside.com 2019 - 2024. All rights reserved.