如何使用foreach克服内存限制

时间:2014-07-18 02:27:56

标签: r memory memory-management foreach parallel-processing

我正在尝试处理>保存在磁盘上的10000 xts对象在加载到R时大约为0.2 GB。我想使用foreach并行处理这些对象。我的代码适用于100 xts对象,我在内存中预先加载,导出等但是在>之后。 100 xts对象我在机器上达到了内存限制。

我想要做的例子:

require(TTR)
require(doMPI)
require(foreach)

test.data <- runif(n=250*10*60*24)

xts.1 <- xts(test.data, order.by=as.Date(1:length(test.data)))
xts.1 <- cbind(xts.1, xts.1, xts.1, xts.1, xts.1, xts.1)

colnames(xts.1) <- c("Open", "High", "Low", "Close", "Volume", "Adjusted")

print(object.size(xts.1), units="Gb")

xts.2 <- xts.1
xts.3 <- xts.1
xts.4 <- xts.1

save(xts.1, file="xts.1.rda")
save(xts.2, file="xts.2.rda")
save(xts.3, file="xts.3.rda")
save(xts.4, file="xts.4.rda")

names <- c("xts.1", "xts.2", "xts.3", "xts.4")

rm(xts.1)
rm(xts.2)
rm(xts.3)
rm(xts.4)

cl <- startMPIcluster(count=2) # Use 2 cores
registerDoMPI(cl)

result <- foreach(name=names, 
                  .combine=cbind, 
                  .multicombine=TRUE, 
                  .inorder=FALSE, 
                  .packages=c("TTR")) %dopar% {
    # TODO: Move following line out of worker. One (or 5, 10,
    # 20, ... but not all) object at a time should be loaded 
    # by master and exported to worker "just in time"
    load(file=paste0(name, ".rda"))

    return(last(SMA(get(name)[, 1], 10)))
}

closeCluster(cl)

print(result)

所以我想知道我怎么能够加载每个(或几个像5,10,20,100,但不是一次全部)xts对象来自磁盘&#34;只是及时&#34;在它们被发送/需要/出口给工人之前。我无法在worker中加载对象(基于存储在磁盘上的名称和文件夹),因为工作人员可以在远程计算机上无法访问存储在磁盘上的对象的文件夹。所以我需要能够及时阅读/加载它们#34;及时#34;在主要过程......

我使用doMPI和doRedis作为并行后端。 doMPI看起来更有效,但比doRedis慢(在100个对象上)。

所以我想了解什么是正确的&#34;策略&#34; /&#34;模式&#34;解决这个问题。

1 个答案:

答案 0 :(得分:3)

除了使用doMPI或doRedis之外,还需要编写一个返回适当迭代器的函数。我的插图中有很多例子&#34;编写自定义迭代器&#34;从iterators包中应该有用,但是这里有一个快速尝试这样的功能:

ixts <- function(xtsnames) {
  it <- iter(xtsnames)

  nextEl <- function() {
    xtsname <- nextElem(it)  # throws "StopIteration"
    load(file=paste0(xtsname, ".rda"))
    get(xtsname)
  }

  obj <- list(nextElem=nextEl)
  class(obj) <- c('ixts', 'abstractiter', 'iter')
  obj
}

这非常简单,因为它基本上是一个围绕着#34;名称&#34;的迭代器的包装器。变量。小插图在几个例子中使用了这种技术。

您可以使用&#34; ixts&#34;与foreach如下:

result <- foreach(xts=ixts(names),
                  .combine=cbind, 
                  .multicombine=TRUE, 
                  .inorder=FALSE, 
                  .packages=c("TTR")) %dopar% {
    last(SMA(xts[, 1], 10))
}

虽然这个迭代器可以与任何foreach后端一起使用,但并非所有后端都会将它称为及时。 doMPI和doRedis会,但是doParallel和doMC预先从迭代器获取所有值,因为clusterApplyLB和mclapply要求所有值都在列表中。 doMPI和doRedis旨在与迭代器一起使用,以提高内存效率。