在Windows中(尚未在Linux中测试(,我正在尝试(令人尴尬地(在大量人群上并行化贝叶斯采样。我正在运行一些测试,并在处理列表对象长度不同的列表时发现了一些非常令人担忧的行为。使用的库有parallel
、snow
、doSNOW
、foreach
和rlecuyer
。
## Set parameters
cores<-4; N<-10004; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Split the population
lst<-suppressWarnings(split(1:N,f=1:cores))
## Initialize cluster
cl <<- parallel::makePSOCKcluster(cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(cores)*1001))
## Export and run test
clusterExport(cl,c("lst"))
system.time(
theta<-as.vector(parSapply(cl,1:cores,function(x) rnorm(length(lst[[x]]),mean=Mean[lst[[x]]],sd=SD)))
)
## validate length
system.time(
n.lst<-as.vector(parSapply(cl,1:cores,function(x) lst[[x]]))
)
## Stop the cluster and check data
parallel::stopCluster(cl)
length(theta) # 10004
length(n.lst) # 10004
现在我将人口更改为不能被 4 整除的数字
## Set parameters
cores<-4; N<-10001; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Run the same code above... And check the output arrays:
length(theta) # 25010000
length(n.lst) # 25010000
所以是的,这个名单呈指数级增长......数组的长度不是 2500+2500+2500+2501,而是 2500*2501*4...这对我来说毫无意义。
事实证明,问题必须出在使用 parSapply
上;我不得不将问题转换为使用parLapply
,我终于得到了一些可接受的结果。当以以下方式重新编码问题时,一切都解决了。注意:我不得不远离split
,因为没有明显的方法来防止它在拆分的索引上运行模数。相反,我创建了一个按顺序拆分向量的函数。
vsplit<-function(x,f) {
setNames(lapply(f,function (y) x[ceiling((1:length(x))/(length(x)/max(f)))==y]),f)
}
PNorm<-function(x) {
rnorm(length(lt[[x]]),lt[[x]],1)
}
settings<-list(); cores<-settings$cores<-4; N<-10000001
Mean<-rnorm(N,sd=0.7)
SD<-1
lt<-suppressWarnings(vsplit(Mean,1:cores))
cl <<- parallel::makePSOCKcluster(settings$cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(settings$cores)*1001))
clusterExport(cl,c("lt"))
system.time(
that<-unlist(parLapply(cl,1:cores,PNorm))
)
length(that)
parallel::stopCluster(cl)