使用R中的foreach读取全局变量

时间:2013-08-03 01:47:18

标签: r foreach parallel-processing

我正在尝试使用RStudio在具有16核CPU和64 GB RAM的Windows服务器上运行foreach循环。 (使用doParallel包)

“worker”进程复制来自for循环外部的所有变量(通过在运行foreach循环时观察windows任务管理器中这些进程的实例化来观察),从而使每个进程使用的内存膨胀。我试图将一些特别大的变量声明为全局变量,同时确保这些变量也在foreach循环中读取,而不是写入,以避免冲突。但是,这些进程仍然会快速耗尽所有可用内存。

是否有机制确保“工作”进程不会创建某些“只读”变量的副本?比如声明这样的变量的具体方法?

1 个答案:

答案 0 :(得分:17)

doParallel包会自动将变量自动导出到foreach循环中引用的worker。如果您不希望它这样做,您可以使用foreach“。noexport”选项来阻止它自动导出特定变量。但是如果我理解正确的话,你的问题是R随后会复制其中的一些变量,这比平常更多问题,因为它发生在一台机器上的多个进程中。

没有办法声明变量,以便R永远不会复制它。您需要使用bigmemory之类的包中的对象替换问题变量,以便永远不会创建副本,或者您可以尝试修改代码,以免触发重复。您可以使用tracemem功能来帮助您,因为只要该对象被复制,它就会打印一条消息。

但是,您可以通过减少工作人员所需的数据来避免此问题。这减少了需要复制到每个工作人员的数据量,并减少了他们的内存占用。

这是给工人提供超出他们需要的数据的典型例子:

x <- matrix(1:100, 10)
foreach(i=1:10, .combine='c') %dopar% {
    mean(x[,i])
}

由于x循环中引用了矩阵foreach,因此它将自动导出到每个工作程序,即使每个工作程序只需要列的子集。最简单的解决方案是迭代矩阵的实际列而不是列索引:

foreach(xc=x, .combine='c') %dopar% {
    mean(xc)
}

不仅将较少的数据传输给工作人员,而且每个工作人员实际上一次只需要在内存中有一列,这大大减少了大型矩阵的内存占用。 xc向量可能仍然最终被复制,但它几乎没有受到太大影响,因为它远小于x

请注意,此技术仅在doParallel使用“雪派生”功能(如parLapplyclusterApplyLB时)时才有用,而不是在使用mclapply时。当使用mclapply时,使用这种技术会使循环变慢,因为所有工作者都可以免费获得矩阵x,那么为什么当工人已经拥有整个矩阵时,在列周围进行转移?但是,在Windows上,doParallel无法使用mclapply,因此这项技术非常重要。

重要的是要考虑工人真正需要哪些数据来执行他们的工作,并尽可能地减少工作量。有时您可以使用iteratorsitertools包中的特殊迭代器来完成此操作,但您也可以通过更改算法来实现此目的。