【问题标题】:How to avoid duplicating objects with foreach如何避免使用 foreach 复制对象
【发布时间】:2013-04-29 08:18:42
【问题描述】:

我有一个非常大的字符串向量,想使用foreachdosnow 包进行并行计算。我注意到foreach 会为每个进程复制向量,从而快速耗尽系统内存。我试图将向量分解为列表对象中的较小部分,但仍然没有看到任何内存使用减少。有人对此有想法吗?下面是一些演示代码:

library(foreach)
library(doSNOW)
library(snow)

x<-rep('some string', 200000000)
# split x into smaller pieces in a list object
splits<-getsplits(x, mode='bysize', size=1000000) 
tt<-vector('list', length(splits$start))  
for (i in 1:length(tt)) tt[[i]]<-x[splits$start[i]: splits$end[i]]

ret<-foreach(i = 1:length(splits$start), .export=c('somefun'), .combine=c)   %dopar% somefun(tt[[i]])

【问题讨论】:

  • 只是一个想法:调用ret&lt;-foreach( k in tt, .export=c('somefun'), .combine=c) %dopar% somefun(k) 时,您是否看到内存消耗下降?
  • 感谢 Beasterfield 的提示,但 foreach 似乎无法识别 in 语法。
  • 对不起,我的意思当然是foreach( k = tt, ... )
  • 有效!我还尝试了iterators 包,iter 用于列表对象和isplit 用于矢量对象避免将大矢量复制到每个进程中。

标签: r parallel-processing mpi


【解决方案1】:

您使用的迭代风格通常与doMC 后端配合良好,因为工作人员可以通过fork 的魔力有效地共享tt。但是使用doSNOWtt 将自动导出给工作人员,使用大量内存,即使他们实际上只需要其中的一小部分。 @Beasterfield 提出的直接迭代 tt 的建议解决了这个问题,但是通过使用迭代器和适当的并行后端,可以提高内存效率。

在这种情况下,我使用 itertools 包中的 isplitVector 函数。它将一个向量拆分为一系列子向量,允许它们并行处理而不会失去向量化的好处。不幸的是,对于doSNOW,它会将这些子向量放入一个列表中,以便在snow 中调用clusterApplyLB 函数,因为clusterApplyLB 不支持迭代器。但是,doMPIdoRedis 后端不会这样做。他们将直接从迭代器将子向量发送给工作人员,使用几乎一半的内存。

这是一个使用doMPI的完整示例:

suppressMessages(library(doMPI))
library(itertools)
cl <- startMPIcluster()
registerDoMPI(cl)
n <- 20000000
chunkSize <- 1000000
x <- rep('some string', n)
somefun <- function(s) toupper(s)
ret <- foreach(s=isplitVector(x, chunkSize=chunkSize), .combine='c') %dopar% {
  somefun(s)
}
print(length(ret))
closeCluster(cl)
mpi.quit()

当我在 4 GB 内存的 MacBook Pro 上运行它时

$ time mpirun -n 5 R --slave -f split.R 

大约需要 16 秒。

您必须注意在同一台机器上创建的工作人员数量,尽管减少 chunkSize 的值可能会让您开始更多。

如果您能够使用不需要所有字符串同时在内存中的迭代器,则可以进一步减少内存使用量。例如,如果字符串在名为“strings.txt”的文件中,您可以使用s=ireadLines('strings.txt', n=chunkSize)

【讨论】:

  • 特别是对于ireadLines,它遵循经理/工人范式,其中工人由单个经理进程产生;有没有办法使用itertools,但以一种更 SPMD 的方式(pbdR-like),这样 R 工作人员的管理就留给 mpirun 了?将流程管理的责任完全交给 mpirun 似乎是一种更好的职责分工。
  • @MartinMorgan:这是一个有趣的想法。我已经使用了基于Rmpi 构建的自己的SPMD 样式包,但我没有考虑在那种情况下使用迭代器,尽管我对在其他情况下使用分布式迭代器的想法很感兴趣。我从未使用过pbdR,但我应该检查一下。
猜你喜欢
  • 2012-05-15
  • 2015-07-30
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
  • 2011-11-25
  • 2017-07-11
相关资源
最近更新 更多