r%dopar%嵌套循环未并行运行
我正在通过使用r%dopar%嵌套循环未并行运行,r,nested-loops,doparallel,parallel-foreach,R,Nested Loops,Doparallel,Parallel Foreach,我正在通过使用%dopar%运行一个嵌套循环,以生成用于体验目的的虚拟数据集。 参考链接: 样本数据集 问题 当我在%dopar%上运行时,我确实使用资源监视器来监视我的机器的CPU性能,我注意到CPU没有得到充分利用 问题: 我确实尝试在我的机器i5上运行上述脚本(test1和test2),4核。但是,似乎%do%和%dopar%的运行时间彼此接近。这是我的脚本设计问题?我的真实数据由50k唯一ID组成,这意味着如果在%do%中运行,将花费很长时间,我如何才能充分利用我的机器CPU来减少运行
%dopar%
运行一个嵌套循环,以生成用于体验目的的虚拟数据集。
参考链接:
样本数据集
问题
当我在%dopar%
上运行时,我确实使用资源监视器来监视我的机器的CPU性能,我注意到CPU没有得到充分利用
问题:
我确实尝试在我的机器i5上运行上述脚本(test1和test2),4核。但是,似乎%do%
和%dopar%
的运行时间彼此接近。这是我的脚本设计问题?我的真实数据由50k
唯一ID组成,这意味着如果在%do%
中运行,将花费很长时间,我如何才能充分利用我的机器CPU来减少运行时间?我相信您已经看到了foreach包的初始开销,因为它复制并设置了正确运行每个循环所需的一切。在运行你的代码大约30-60秒后,我的cpu的利用率太高了,直到代码最终完成
也就是说,它不能解释为什么您的代码比%do%
循环慢。我相信这里的罪魁祸首在于当您试图访问所有foreach循环中的数据时,foreach循环是如何应用的。基本上,如果您不这样做。导出您需要的数据,它将尝试在几个并行会话中访问相同的数据,并且每个会话将不得不等待,而其他会话将完成访问自己的数据。
使用foreach中的.export
参数导出数据可能会缓解这一问题。就我个人而言,我使用其他软件包来执行我的大部分并行化,所以如果这是您想要的,我建议进行测试。然而,这将带来更大的开销
更快的方法:
现在,当您试图创建一个虚拟数据集时,对于该数据集,某些列的所有组合都被组合在一起,有一些更快的方法可以获得该数据集。快速搜索“交叉连接”将
对于data.table软件包,使用“CJ”功能可以非常高效和快速地完成。简单地
output <- CJ(ID, year, month)
输出相关:看起来所有CPU上都有运行的东西,这可能是Windows对每个CPU施加的限制吗?嗨@Oliver,谢谢你的评论!通过应用您的建议,CJ功能对我的交叉连接问题非常有效。您是对的,我遇到了开销问题,尤其是在运行并行处理时,涉及到rbind
,很高兴您给出了导致开销问题的重要因素(缺少.export
语句)。:)你好@Oliver,我可以知道你通常使用哪种parallization软件包吗?没问题,我很高兴能帮上忙。对于我自己的编程,我最经常使用并行包本身。许多问题可以用parApply或Parlappy解决(如果输出不是类似矩阵的)。然而,在任何情况下,如果问题可以分为几个块,并且并行化可以分为这些块,而不必迭代许多较小的问题,则可以获得很大的好处。每次迭代都会增加一点开销(在大多数情况下是很小的),因此让4个进程执行所有工作,而不是100个进程在较小的块中执行同样的工作会更好。对于使用futures
(或furr
)的非标准并行进程,承诺
,ipc
包可以帮助执行异步并行化,尽管它变得更加技术化,并且需要一些时间来研究这个问题。我相信foreach可以利用迭代器块状结构来执行大小等于或小于内核数的块计算,而不是通过一个小迭代器来执行。然而,我仍然要研究这个属性,这可能使foreach包在一些非标准情况下更快。
library(foreach)
library(data.table)
library(doParallel)
# parallel processing setting
cl <- makeCluster(detectCores() - 1)
registerDoParallel(cl)
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
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
> view(output_table)
output <- CJ(ID, year, month)