【问题标题】:nested foreach loops in R to update common arrayR中的嵌套foreach循环以更新公共数组
【发布时间】:2013-07-04 16:47:02
【问题描述】:

我试图在 R 中使用几个 foreach 循环来并行填充一个公共数组。我正在尝试做的一个非常简化的版本是:

library(foreach)
set.seed(123)
x <- matrix(NA, nrow = 8, ncol = 2)

foreach(i=1:8) %dopar% {
    foreach(j=1:2) %do% {

      l <- runif(1, i, 100)
      x[i,j] <- i + j + l     #This is much more complicated in my real code.   

    }
}

我想编写代码以并行更新矩阵x 并使输出如下所示:

> x
       [,1]      [,2]
 [1,]  31.47017  82.04221
 [2,]  45.07974  92.53571
 [3,]  98.22533  12.41898
 [4,]  59.69813  95.67223
 [5,]  63.38633  55.37840
 [6,] 102.94233  56.61341
 [7,]  78.01407  69.25491
 [8,]  26.46907 100.78390 

但是,我似乎无法弄清楚如何更新数组。我曾尝试将x &lt;- 放在别处,但它似乎不喜欢它。我认为这将是一件很容易解决的事情,但我所有的搜索还没有把我带到那里。谢谢。

【问题讨论】:

  • 您好,只是一般提示:如果使用特定的包,在示例代码中指出这一点会很有帮助。 (我已经编辑了您的代码以反映)
  • 谢谢@RicardoSaporta 我忘了在做小例子时这样做

标签: r foreach parallel-processing


【解决方案1】:

foreach 循环用于返回值,如lapply。通过这种方式,它们与用于副作用的for 循环非常不同。通过使用适当的.combine 函数,内部foreach 循环可以返回由外部foreach 循环按行组合成矩阵的向量:

x <- foreach(i=1:8, .combine='rbind') %dopar% {
   foreach(j=1:2, .combine='c') %do% {
     l <- runif(1, i, 100)
     i + j + l  
   }
}

也可以使用嵌套运算符:%:%:

x <- foreach(i=1:8, .combine='rbind') %:%
   foreach(j=1:2, .combine='c') %dopar% {
     l <- runif(1, i, 100)
     i + j + l  
   }

请注意,set.seed 可能不会做你想做的事,因为它是在本地机器上执行的,而随机数是在不同的 R 会话中生成的,可能在不同的机器上。

【讨论】:

  • 没有意识到 set.seed 的这一点——感谢您指出这一点
【解决方案2】:

只是在史蒂夫的回答中添加一些内容:我认为关键点是并行后端启动了多个 Rscript.exe 进程(可以在任务管理器中看到)。 在foreach 中使用的某些对象,即在您的情况下为x,然后复制到为每个进程分配的内存中。我不确定foreach 包中的复制是如何处理的,但是使用plyr 包的*ply 函数,您必须明确说明应该复制的对象。 不同的进程不共享它们的内存。 (我不知道其他可以使用共享内存的 R 包...)

可以证明矩阵x实际上是通过使用.Internal(inspect(x))打印对象x的内存位置来复制的。

library(foreach)
library(doParallel)

x <- matrix(1:16, nrow = 8, ncol = 2)
#print memory location of x
capture.output(.Internal(inspect(x)))[1]

#create parallel backend; in our case two Rscript.exe processes
workers=makeCluster(2)
registerDoParallel(workers)

y<- foreach(i=1:8, .combine='rbind') %dopar% {
    #return memory location of x
    capture.output(.Internal(inspect(x)))[1]
}

#print matrix y
#there should be two different memory locations - 
#according to the two Rscript.exe processes started above
y

#close parallel backend
stopCluster(workers)

矩阵y 读取

       [,1]                                                                          
result.1 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(1),ATT] (len=16, tl=0) 1,2,3,4,5,..."
result.2 "@0x0000000003dab9b0 13 INTSXP g0c5 [NAM(1),ATT] (len=16, tl=0) 1,2,3,4,5,..."
result.3 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(2),ATT] (len=16, tl=0) 1,2,3,4,5,..."
result.4 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(2),ATT] (len=16, tl=0) 1,2,3,4,5,..."
...

你应该在那里找到两个不同的内存地址。

【讨论】:

    猜你喜欢
    • 2019-07-13
    • 2016-05-28
    • 2015-07-17
    • 2016-07-25
    • 1970-01-01
    • 2015-12-14
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多