我正在使用%dopar%
运行嵌套循环,以生成用于经验目的的虚拟数据集。
参考链接: R nested foreach %dopar% in outer loop and %do% in inner loop
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)
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)
当我在%dopar%
上运行时,确实使用Resource Monitor
监视了计算机的CPU性能,并且我发现CPU没有得到充分利用。
我确实尝试在我的机器i5(4核)上运行以上脚本(test1和test2)。但是似乎%do%
和%dopar%
的运行时间都彼此接近。这是我的脚本设计问题吗?我的真实数据由50k
唯一ID组成,这意味着如果在%do%
中运行将花费很长时间,那么我如何充分利用机器的CPU来减少运行时间?
答案 0 :(得分:1)
我相信您会看到foreach软件包的初始开销,因为它复制并设置了正确运行每个循环所需的内容。在运行您的代码大约30至60秒后,我的CPU的利用率都太高了,直到代码完成为止。
也就是说,它不能解释为什么您的代码与%do%
循环相比如此之慢。我认为,当您尝试访问所有foreach循环中的数据时,最主要的问题是如何应用foreach循环。基本上,如果您不导出所需的数据,它将尝试在多个并行会话中访问相同的数据,并且每个会话将不得不等待其他会话完成其自身数据的访问。
通过使用foreach中的.export
参数导出数据,可以缓解这种情况。就我个人而言,我使用其他程序包来执行大部分的并行处理,因此,如果您要这样做,我建议您对此进行测试。但是,这会带来更大的开销。
现在,当您尝试创建一个虚拟数据集时,将某些列的所有组合都合并在一起,因此有更快的方法来获取此数据集。快速搜索“交叉连接”将lead you to posts like this one.
对于data.table包,可以使用'CJ'功能非常高效和快速地完成。只是
output <- CJ(ID, year, month)
将产生您的嵌套循环尝试创建的结果,只需花费约0.07秒的时间即可完成任务。