简体   繁体   English

%dopar%或其他方法可加快顺序随机计算

[英]%dopar% or alternative method to speed up sequential stochastic calculation

I have written a stochastic process simulator but I would like to speed it up since it's pretty slow. 我已经编写了一个随机过程模拟器,但是我想加快它的速度,因为它相当慢。

The main part of the simulator is made of a for loop which I would like to re-write as a foreach with `%dopar%. 模拟器的主要部分由for循环组成,我想用`%dopar%重写为foreach

I have tried doing so with a simplified loop but I'm running into some problems. 我尝试使用简化的循环来执行此操作,但是遇到了一些问题。 Suppose my for loop looks like this 假设我的for循环看起来像这样

library(foreach)

r=0
t<-rep(0,500)
for(n in 1:500){
    s<-1/2+r
    u<-runif(1, min = 0, max = 1)
    if(u<s){
        t[n]<-u
        r<-r+0.001
    }else{r<-r-0.001}
}

which means that at each iteration I update the value of r and s and, in one of the two outcomes, populate my vector t . 这意味着在每次迭代中,我都会更新rs的值,并在两个结果之一中填充向量t I have tried several different ways of re-writing it as a foreach loop but it seems like with each iteration my values don't get updated and I get some pretty strange results. 我尝试了几种不同的方式将其重写为foreach循环,但似乎每次迭代时我的值都没有更新,并且得到了一些非常奇怪的结果。 I have tried using return but it doesn't seem to work! 我已经尝试过使用return但是它似乎不起作用!

This is an example of what I have come up with. 这是我想出的一个例子。

rr=0
tt<-foreach(i=1:500, .combine=c) %dopar% {
    ss<-1/2+rr
    uu<-runif(1, min = 0, max = 1)
    if(uu<=ss){
        return(uu)
        rr<-rr+0.001
    }else{
        return(0)
        rr<-rr-0.001}
}

If it is impossible to use foreach what other way is there for me to re-write the loop so to be able to use all cores and speed up things? 如果无法使用foreach还有什么其他方法可以让我重写循环,以便能够使用所有内核并加快处理速度?

Since your comments, about turning to C, were encouraging and -mostly- to prove that this isn't a hard task (especially for such operations) and it's worth looking into, here is a comparison of two sample functions that accept a number of iterations and perform the steps of your loop: 由于您关于转向C的评论令人鼓舞,并且(主要是)证明这不是一件艰巨的任务(尤其是对于此类操作),并且值得研究,因此这里比较了两个接受多个示例函数的示例函数迭代并执行循环步骤:

ffR = function(n) 
{
   r = 0
   t = rep(0, n)
   for(i in 1:n) {
       s = 1/2 + r
       u = runif(1)
       if(u < s) {
           t[i] = u
           r = r + 0.001
       } else r = r - 0.001
   }

   return(t)
}


ffC = inline::cfunction(sig = c(R_n = "integer"), body = '
    int n = INTEGER(AS_INTEGER(R_n))[0];

    SEXP ans;
    PROTECT(ans = allocVector(REALSXP, n));

    double r = 0.0, s, u, *pans = REAL(ans);

    GetRNGstate();

    for(int i = 0; i < n; i++) {
        s = 0.5 + r;
        u = runif(0.0, 1.0);

        if(u < s) {
            pans[i] = u;
            r += 0.001;
        } else {
            pans[i] = 0.0;
            r -= 0.001;
        }
    }

    PutRNGstate();

    UNPROTECT(1);
    return(ans);
', includes = "#include <Rmath.h>")

A comparison of results: 结果比较:

set.seed(007); ffR(5)
#[1] 0.00000000 0.39774545 0.11569778 0.06974868 0.24374939
set.seed(007); ffC(5)
#[1] 0.00000000 0.39774545 0.11569778 0.06974868 0.24374939

A comparison of speed: 速度比较:

microbenchmark::microbenchmark(ffR(1e5), ffC(1e5), times = 20)
#Unit: milliseconds
#       expr        min         lq     median         uq        max neval
# ffR(1e+05) 497.524808 519.692781 537.427332 668.875402 692.598785    20
# ffC(1e+05)   2.916289   3.019473   3.133967   3.445257   4.076541    20

And for the sake of completeness: 为了完整起见:

set.seed(101); ans1 = ffR(1e5)
set.seed(101); ans2 = ffC(1e5)
all.equal(ans1, ans2)
#[1] TRUE

Hope any of this could be helpful in some way. 希望以上任何一种方式都能有所帮助。

What you are trying to do, since every iteration is dependent on the previous steps of the loop, doesn't seem to be parallelizable. 由于每个迭代都取决于循环的先前步骤,因此您要尝试执行的操作似乎不可并行化。 You are updating the variable r and expecting other branches that are running simultaneously to know about it, and in fact wait for the update to happen, which 您正在更新变量r,并期望同时运行的其他分支知道该变量,并且实际上等待更新发生,这
1) Doesn't happen. 1)不会发生。 They won't wait, they'll just take r's current value whatever that is at the time they are running 他们不会等待,他们只会将r的当前值作为运行时的值
2) If it did it would be same as running it without %dopar% 2)如果这样做,则与没有%dopar%情况下运行它相同

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM