【发布时间】:2017-07-19 00:18:02
【问题描述】:
我在R中使用foreach + doParallel对矩阵的每一行多线程应用一个函数。当矩阵有很多行时,foreach前后需要很长时间多线程遍历迭代。
例如,如果我运行:
library(foreach)
library(doParallel)
doWork <- function(data) {
# setup parallel backend to use many processors
cores=detectCores()
number_of_cores_to_use = cores[1]-1 # not to overload the computer
cat(paste('number_of_cores_to_use:',number_of_cores_to_use))
cl <- makeCluster(number_of_cores_to_use)
clusterExport(cl=cl, varlist=c('ns','weights'))
registerDoParallel(cl)
cat('...Starting foreach initialization')
output <- foreach(i=1:length(data[,1]), .combine=rbind) %dopar% {
cat(i)
y = data[i,5]
a = 100
for (i in 1:3) { # Useless busy work
b=matrix(runif(a*a), nrow = a, ncol=a)
}
return(runif(10))
}
# stop cluster
cat('...Stop cluster')
stopCluster(cl)
return(output)
}
r = 100000
c = 10
data = matrix(runif(r*c), nrow = r, ncol=c)
output = doWork(data)
output[1:10,]
CPU使用率如下(100%表示所有核心都被充分利用):
带注释:
如何优化代码以使foreach 在多线程迭代之前和之后不需要很长时间?主要时间槽是之后花费的时间。 after 所花费的时间随着 foreach 迭代次数的增加而显着增加,有时会使代码变慢,就像使用了简单的 for 循环一样。
另一个例子(假设lm 和poly 不能将矩阵作为参数):
library(foreach)
library(doParallel)
doWork <- function(data,weights) {
# setup parallel backend to use many processors
cores=detectCores()
number_of_cores_to_use = cores[1]-1 # not to overload the computer
cat(paste('number_of_cores_to_use:',number_of_cores_to_use))
cl <- makeCluster(number_of_cores_to_use)
clusterExport(cl=cl, varlist=c('weights'))
registerDoParallel(cl)
cat('...Starting foreach initialization')
output <- foreach(i=1:nrow(data), .combine=rbind) %dopar% {
x = sort(data[i,])
fit = lm(x[1:(length(x)-1)] ~ poly(x[-1], degree = 2,raw=TRUE), na.action=na.omit, weights=weights)
return(fit$coef)
}
# stop cluster
cat('...Stop cluster')
stopCluster(cl)
return(output)
}
r = 10000
c = 10
weights=runif(c-1)
data = matrix(runif(r*c), nrow = r, ncol=c)
output = doWork(data,weights)
output[1:10,]
【问题讨论】:
-
我认为问题出在
rbind。rbind列表中的大量值需要很长时间。此外,填充行是不好的,因为矩阵是按列存储的。此外,制作长 foreach 循环效率不高(改用块)。最后,在矩阵上并行化时,使用共享内存总是更好。如果您提出一个与您想要的更接近的示例,我可以为您制定解决方案。 -
问题在于认为
foreach %dopar%总是比矢量化方法快。foreach %dopar%需要在工作人员的100,000实例之间进行通信,因为您正在迭代i=1:length(data[,1])和data有 100,000 行。在实施并行化方法之前,您应该在矢量化方法(sapply、lapply、apply)和并行化方法之间进行基准测试。如果您想坚持使用并行化方法,请将您的代码更改为处理列(其中有 10 个)而不是行。最好是让更少的工人开始,每个人都做更多的工作。 -
@F.Privé 谢谢,我会很感兴趣。我添加了一个与我想要的更接近的示例。
-
x = sort(data[i,])和x[1:(length(x)-1)]看起来很奇怪。你能确认这是你想做的吗? -
@F.Privé 已确认。感谢您的精彩回答!
标签: r multithreading foreach