我正在使用R中的doParallel / Foreach后端并行运行一个进程。我正在注册一组20个核心作为一个集群,并运行该过程大约100次。我将矩阵传递给并行进程的每次迭代,并且在子进程中,我用自己行的随机样本替换矩阵。我想知道的是:我是否应该期望这种修改在同一子进程处理的后续迭代中持续存在?例如,当子进程1完成第一次迭代时,它是用原始矩阵或随机样本开始第二次迭代吗?
一个最小的例子:
library(doParallel)
X <- matrix(1:400, ncol=4)
cl<-makeCluster(2)
clusterExport(X)
registerDoParallel(cl)
results<-foreach(i=1:100) %dopar% {
set.seed(12345)
X <- X[sample.int(nrow(X),replace=TRUE),]
X
}
修改
要明确的是,如果对象确实会在同一个工作进程的迭代中持续存在,那么这不是我想要的行为。相反,我想让每次迭代都采用原始矩阵的新随机样本,而不是最近随机样本的随机样本(我认识到在我的最小例子中它还会创建相同随机每次原始矩阵的样本,由于种子集 - 在我的实际应用中我处理这个。)
答案 0 :(得分:1)
群集工作程序中的副作用可能在foreach循环的迭代中持久存在,但这不是foreach支持的功能。利用它的程序可能无法移植到不同的并行后端,并且可能无法与较新版本的软件一起使用。事实上,当我第一次写foreach时,我试图使这种副作用变得不可能,但我最终放弃了。
请注意,在您的情况下,您不会修改显式导出到工作人员的X
副本:您正在修改由doParallel自动导出到工作人员的副本。这可能是你混淆的原因。
如果你真的想这样做,我建议你关闭X
的自动导出,然后修改显式导出的副本,这样程序应该很好地定义和移植,虽然有点难看。这是一个例子:
library(doParallel)
cl <- makePSOCKcluster(2)
registerDoParallel(cl)
X <- matrix(0, nrow=4, ncol=4)
clusterExport(cl, 'X')
ignore <- clusterApply(cl, seq_along(cl), function(i) ID <<- i)
results <-
foreach(i=1:4, .noexport='X') %dopar% {
X[i,] <<- ID
X
}
finalresults <- clusterEvalQ(cl, X)
results
包含每个任务后的矩阵,finalresults
在foreach循环完成后包含每个工作人员的矩阵。
更新
通常,foreach循环的主体不应修改foreach循环之外的任何变量。我只修改我之前在foreach循环的同一次迭代中创建的变量。如果要创建仅在该迭代中使用的修改版本,请使用其他变量名称。