Snow/doSNOW并行环境下rlecuyer随机数生成器内循环重置咨询
解决方案
问题根源
你原有代码的核心错误是误用了set.seed()函数恢复RNG状态:set.seed()的设计用途是通过单个整数初始化随机数生成器,而非恢复完整的RNG状态向量,同时该操作会默认将RNG类型切回系统默认的Mersenne-Twister,破坏了snow框架为每个worker配置的L'Ecuyer-CMRG独立随机流,因此无法达到预期效果。
实现方案
snow启动的每个worker进程是完全隔离的,各自的RNG状态独立存储,无需额外定位子流,直接操作当前进程的.Random.seed变量即可完成状态的保存和恢复,且不会干扰其他并行实例的随机流独立性。
注意:.Random.seed默认存储在R的全局环境中,在foreach的执行环境内直接赋值会创建局部变量,无法修改实际生效的全局RNG状态,因此需要使用<<-超赋值操作符修改全局环境中的.Random.seed。
修正后代码
library(doSNOW) library(rlecuyer) seed = 4711 cl = makeCluster(2) registerDoSNOW(cl) # 为每个worker配置独立的L'Ecuyer-CMRG随机流 clusterSetupRNGstream(cl, seed=rep(seed,6)) erg = foreach(irun = 1:3,.combine = rbind) %dopar% { # 外层循环随机逻辑,不受内循环影响 smp = runif(1) # 保存当前L'Ecuyer流的完整状态 rng_state <- .Random.seed idx = numeric(5) for(ii in seq.int(5)) { idx[ii] = sample.int(10, 1) # 直接恢复保存的RNG状态 .Random.seed <<- rng_state } c(smp, idx) } stopCluster(cl) print(erg)
预期输出示例
[,1] [,2] [,3] [,4] [,5] [,6] result.1 0.5749162 7 7 7 7 7 result.2 0.1208910 4 4 4 4 4 result.3 0.3491315 9 9 9 9 9
效果说明
- 每行的后5个整数完全相同,满足内循环每次迭代使用同一组随机数的要求
- 不同行的整数取值不同,外层
smp的取值也相互独立,符合并行随机流的独立性要求 - 无需预生成全部随机数,内循环可以动态生成当前批次所需的随机数据,内存占用更低
内容的提问来源于stack exchange,提问作者g g
相关产品推荐
相关产品推荐

