在并行计算中实现完全可重复的结果

3

我想知道如何使结果可重现。我运行了多次,结果向量却不同。感谢任何帮助。

cl <- makeCluster(2)

registerDoParallel(2)

set.seed(123)

results <- unlist(llply(seq_along(1:4), .fun = function(x){
  runif(1)} ,.parallel = T, 
  .paropts = list(.export=ls(.GlobalEnv))))


stopCluster(cl)
1个回答

4
以下示例可在Linux、Mac OS X和Windows上获得可重复的结果:
library(plyr)
library(doParallel)
cl <- makeCluster(2)
registerDoParallel(cl)
opts <- list(preschedule=TRUE)
clusterSetRNGStream(cl, 123)
r <- llply(1:20,
           .fun = function(x) runif(10),
           .parallel = TRUE,
           .paropts = list(.options.snow=opts))

需要使用preschedule=TRUE选项,以防止doParallel使用负载平衡,这会使任务与工作进程的映射变得不可预测。

如果您正在使用Linux或Mac OS X并希望doParallel使用mclapply,则可以使用以下方法:

if (.Platform$OS.type != "windows") {
  registerDoParallel(2)
  RNGkind("L'Ecuyer-CMRG")
  set.seed(123)
  mc.reset.stream()
  r <- llply(1:20,
             .fun = function(x) runif(10),
             .parallel = TRUE)
}

这是因为mclapply默认使用预调度。在Windows系统上无法工作,因为doParallel将隐式创建一个集群对象,而RNG初始化不会产生任何影响。
请注意,在您的示例中,您正在创建一个集群对象但未注册它,因此doParallel不会使用它。您必须使用registerDoParallel(cl),否则doParallel将在Posix计算机上使用mclapply,或在Windows计算机上隐式创建一个集群对象。明显,初始化实际执行并行计算的集群工作者非常重要。

感谢您详细的回答,太棒了!是的,我正在尝试编写适用于任何操作系统的代码。因此,您提供的第一种解决方案是我正在使用的。谢谢!让我问您一些后续问题:.options.multicore和.options.snow之间有什么区别?为什么您使用向量c(1,2,3,4,5,6,7)作为set.seed而不是整数?如果您有一个具有“set.seed(1234)”的自定义函数而不是runif(10),那么应该删除该set.seed以避免新的多线程冲突,从而无法实现可重复性? - donpresente
1
@donpresente。.options.multicore仅由“mclapply”后端使用,而.options.snow仅由“cluster”后端使用。它允许您传递特定于后端的选项,而不会失去可移植性。 - Steve Weston
1
@donpresente 我应该将123传递给clusterSetRNGStream。我混淆了一些使用L'Ecuyer-CMRG生成器的7个整数种子的内部函数。我已经在我的答案中纠正了这个错误。 - Steve Weston
太棒了!再次感谢!三篇文章讲解并行化的整个课程 :) - donpresente

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接