我试图在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 <-
放在其他地方,但似乎并不喜欢它。我认为这将是一个非常容易解决的问题,但我所有的搜索还没有把我带到那里。感谢。
答案 0 :(得分:13)
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会话中生成的,可能在不同的计算机上生成。
答案 1 :(得分:2)
只是为Steve的回答添加一些内容:我认为关键点是并行后端启动多个Rscript.exe进程(可以在任务管理器中看到)。
然后将foreach
中使用的某些对象(例如在您的x
中)复制到为每个进程分配的内存中。我不确定如何在foreach
包中处理复制,但是使用*ply
包的plyr
函数,您必须明确说明应该复制的对象。
不同的流程不共享他们的记忆。 (我不知道其他可以使用共享内存的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,..."
...
你应该在那里找到两个不同的内存地址。