我写了一个(可能是低效的,但无论如何......)Rcpp代码,使用内联来模拟随机SEIR model。
串行版本编译和工作完美,但因为我需要从它模拟很多次,因为在我看来,这似乎是一个令人尴尬的并行问题(只需要再次模拟其他参数值并返回带结果的矩阵)我尝试添加#pragma omp parallel for
并使用-fopenmp -lgomp
进行编译但是......繁荣!
即使是非常小的例子,我也会遇到段错误!
我尝试添加setenv("OMP_STACKSIZE","24M",1);
和超过24M的值,但仍然发生了段错误。
我将简要解释代码,因为它有点长(我试图缩短它但结果改变了,我无法重现它......): 我有两个嵌套循环,内部循环执行给定参数集的模型,外部循环更改参数。
竞争条件可能发生的唯一原因是代码是否试图并行执行 inner 循环内部的指令集(由于模型结构无法完成,在迭代{{ 1}}它取决于迭代t
)而不是并行化外部,但是如果我没有弄错那就是t-1
构造函数默认为默认情况下在外面......
这基本上是我试图运行的代码的形式:
parallel for
我的问题是:我如何告诉编译器我只想并行计算外部循环(甚至静态地为每个线程分配它们,如n_loops / n_threads)而不是内部循环(实际上是不可并行化的) ?
真正的代码涉及更多,如果你真的愿意,我会在这里为了重现性而提供它,但我只是询问OpenMP的行为。请注意,唯一的OpenMP指令显示在第mat result(n_param,T_MAX);
#pragma omp parallel for
for(int i=0,i<n_param_set;i++){
t=0;
rowvec jnk(T_MAX);
while(t < T_MAX){
...
jnk(t) = something(jnk(t-1));
...
t++;
}
result.row(i)=jnk;
}
return wrap(result);
行。
122
感谢您的帮助!
注意:在你问之前,我稍微修改了Rcpp多项式采样函数,因为我喜欢这种方式而不是使用指针...不是任何其他特殊原因! :)
答案 0 :(得分:1)
R中的核心伪随机数生成器(PRNG)并非设计用于多线程环境。也就是说,它们的状态存储在静态数组(dummy
中的src/main/PRNG.c
)中,因此在所有线程之间共享。此外,还使用了其他几种静态结构来存储核心PRNG的更高级接口的状态。
一种可能的解决方案可能是您将每个调用rnorm()
或其他采样函数放在命名的关键部分中,所有这些函数都具有相同的名称,例如:
...
#pragma omp critical(random)
rN(k) = ((pp < 1.) ? (rbinom(1,(double) n, pp))(0) : n);
...
if((rates(0)+rates(6))>0){
#pragma omp critical(random)
nX = rbinom(1,S_prev,1-exp(-(rates(0)+rates(6))*tau))(0);
...
请注意,critical
构造对其后面的结构化块进行操作,因此会锁定整个语句。如果在对耗时函数的调用中内联绘制随机数,例如
#pragma omp critical(random)
x = slow_computation(rbinom(...));
这更好地转变为:
#pragma omp critical(random)
rb = rbinom(...);
x = slow_computation(rb);
这样只会保护rb = rbinom(...);
语句。