16

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

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

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

4

1 回答 1

21

doParallel包将自动将变量导出到foreach循环中引用的工作人员。如果您不希望它这样做,您可以使用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使用“雪派生”函数时有帮助,例如parLapplyand clusterApplyLB,而不是在使用mclapply. 使用这种技术可以使循环在mclapply使用时变慢一些,因为所有的工作人员都x免费获得矩阵,那么当工作人员已经拥有整个矩阵时,为什么要围绕列进行转移呢?但是,在 Windows 上,doParallel不能使用mclapply,所以这项技术非常重要。

重要的是要考虑工人真正需要哪些数据来执行他们的工作,并尽可能减少它。有时你可以通过使用特殊的迭代器来做到这一点,无论是来自iteratorsoritertools包,但你也可以通过改变你的算法来做到这一点。

于 2013-08-05T13:27:19.887 回答