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



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

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

是否有一种机制可以确保"工作"进程不会创建某些"只读"变量的副本?比如用一种特定的方式来声明这样的变量?

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

没有一种方法可以声明一个变量,这样R就永远不会复制它。你要么需要用像bigmemory这样的包中的对象替换问题变量,这样就永远不会进行复制,要么你可以尝试修改代码,这样就不会触发复制。您可以使用tracemem函数来帮助您,因为每当对象重复时,它都会打印一条消息。

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

这里有一个典型的例子,可以为工人提供比他们需要的更多的数据:

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

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

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

不仅传输到工作者的数据更少,而且每个工作者实际上一次只需要在内存中有一列,这大大减少了其对大型矩阵的内存占用。xc矢量最终可能仍会被复制,但它不会造成太大的伤害,因为它比x小得多。

请注意,此技术仅在doParallel使用"雪衍生"函数(如parLapplyclusterApplyLB)时才有帮助,而在使用mclapply时没有帮助。当使用mclapply时,使用此技术可以使循环稍微慢一点,因为所有工作人员都可以免费获得矩阵x,那么,当工作人员已经拥有整个矩阵时,为什么要在列之间转移呢?然而,在Windows上,doParallel不能使用mclapply,因此该技术非常重要。

重要的是要考虑工人为了完成工作真正需要什么数据,并尽可能减少数据。有时,您可以使用iteratorsitertools包中的特殊迭代器来实现这一点,但也可以通过更改算法来实现。

最新更新