我正在尝试使用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
to 更改为仅do
按顺序而不是并行运行时,它将返回36.65
.
如果我这样做registerDoParallel(6)
会将并行时间缩短到42.11
但仍然比顺序慢. registerDoParallel(8)
变得40.31
比连续更糟糕.
如果我增加到trials
100,000,那么顺序运行需要417.16
和3个工作程序的并行运行597.31
.它需要6名工人425.85
.
我的系统是
戴尔Optiplex 990
Windows 7专业版64位
16GB RAM
英特尔i-7-2600 3.6GHz四核,具有超线程功能
我在这里做错了吗?如果我做了我能想到的最人为的事情(用计算代码替换Sys.sleep(1)
),那么我得到的实际减少量与工人数量成正比.我想知道为什么指南中的例子会降低我的表现,而对他们来说它会加快速度?
根本问题是为PSOCK集群的工作者doParallel
执行attach
每个任务执行,以便将导出的变量添加到包搜索路径.这解决了各种范围问题,但可能会严重影响性能,尤其是对于持续时间较短的任务和大量导出的数据.这种情况在Linux和Mac OS X上不会发生在您的示例中,因为它们将使用mclapply
而不是clusterApplyLB
,但如果您明确注册PSOCK群集,它将在所有平台上发生.
我相信我已经找到了如何解决在不影响性能不同的方式任务范围界定问题,我与革命分析工作得到修复进入的下一个版本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
.它还导致更少但更大的套接字操作,这可以在大多数系统上更有效地执行,但在这种情况下,关键问题是attach
.