我正在尝试使用doParallel和foreach包,但是我使用此处CRANpage中的指南中的bootstrapping示例来降低性能。
library(doParallel)
library(foreach)
registerDoParallel(3)
x <- iris[which(iris[,5] != "setosa"), c(1,5)]
trials <- 10000
ptime <- system.time({
r <- foreach(icount(trials), .combine=cbind) %dopar% {
ind <- sample(100, 100, replace=TRUE)
result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))
coefficients(result1)
}
})[3]
ptime
此示例返回56.87
。
当我将dopar
更改为仅do
以按顺序而不是并行运行时,它会返回36.65
。
如果我registerDoParallel(6)
,它会将并行时间缩短到42.11
,但仍然比顺序时间慢。 registerDoParallel(8)
使40.31
仍然比顺序更差。
如果我将trials
增加到100,000,则顺序运行需要417.16
,而3名工作人员的并行运行需要597.31
。平行6名工人需要425.85
。
我的系统是
Dell Optiplex 990
Windows 7 Professional 64位
16GB RAM
英特尔i-7-2600 3.6GHz四核超线程
我在这里做错了吗?如果我做了我能想到的最人为的事情(用Sys.sleep(1)
替换计算代码),那么我得到的实际减少量与工人数量成正比。我想知道为什么指南中的例子会降低我的表现,而对他们来说它会加快速度?
答案 0 :(得分:9)
潜在的问题是doParallel
为PSOCK集群的worker上的每个任务执行执行attach
,以便将导出的变量添加到包搜索路径。这解决了各种范围问题,但可能会严重影响性能,尤其是对于持续时间较短的任务和大量导出的数据。这个不会在Linux和Mac OS X上与您的示例一起发生,因为它们将使用mclapply
而不是clusterApplyLB
,但如果您明确地将在所有平台上发生注册PSOCK群集。
我相信我已经找到了如何以不影响性能的不同方式解决任务范围问题,并且我正在使用Revolution Analytics来修复{{1}的下一版本和doParallel
,也有同样的问题。
您可以使用任务分块解决此问题:
doSNOW
这导致每个工作只有一个任务,因此每个工作只执行ptime2 <- system.time({
chunks <- getDoParWorkers()
r <- foreach(n=idiv(trials, chunks=chunks), .combine='cbind') %dopar% {
y <- lapply(seq_len(n), function(i) {
ind <- sample(100, 100, replace=TRUE)
result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))
coefficients(result1)
})
do.call('cbind', y)
}
})[3]
一次,而不是attach
次。它还导致更少但更大的套接字操作,这可以在大多数系统上更有效地执行,但在这种情况下,关键问题是trials / 3
。