1

我在 R 中使用 doMPI来并行保存netCDF气候数据。该数据以 4 维矩阵的形式存储在 R 中m,其中包含 6 个变量的数据,在 20000 个时间点,在一个纬度和经度网格上。m因此被索引为m[lon,lat,time,variable]。根据 netCDF 将其数据存储在磁盘上的方式,将数据写入磁盘的最有效方式是按时间片。因此,我想m为每个变量一次迭代一个时间片。目前,我的代码如下所示:

    ntime <- 20000
    output.vars <- list("rainfall", "snowfallwateq", "snowmelt", "newsnow", "snowdepth", "swe") 
    for (var.index in seq_along(output.vars)) {
        ncout <- nc_open(output.files[var.index], write=TRUE)

        val <- foreach(time.index=1:ntime, .packages=c("ncdf4")) %dopar%
        {
            ncvar_put(ncout, output.vars[[var.index]], 
                      vals=m[,,time.index,var.index],
                      start=c(1, 1, time.index),
                      count=c(nlon, nlat, 1))
        }

        nc_close(ncout)
    }

这不必要地将整个m矩阵复制到每个工人。这占用了大量的内存,我需要减少复制的数据量。我从这个答案中想到的是我可以迭代矩阵的每个时间片,因此每次迭代时只有时间片的数据被复制到每个工作人员。该foreach构造允许多个对象同时迭代,因此我什至可以将时间索引与矩阵时间片放在一起而不会出现问题。不幸的是,我不知道有任何方法可以按时间片迭代矩阵。有没有办法做到这一点,这样在变量循环的每次迭代t中,我都可以有一个保存二维矩阵的变量?foreachvardatam[,,t,var]

我已经尝试过下面的直观方法,但它会遍历每个单独的元素,而不是一次遍历整个时间片。

val <- foreach(time.index=1:ntime, slice=m[,,,var], ...
4

1 回答 1

0

如果您可以在主 R 进程中处理您的数据,您可以尝试将每个二维切片转换为big.matrix包中的一个bigmemory,并在您的并行工作人员中使用它。这仅在从属进程中处理每个切片所需的时间很长时才有用。

请参阅此示例,并注意您可以嵌套 2 个foreach循环%:%

m <- as.numeric(1:16)
dim(m) <- rep(2L, 4L)

# use %do% for sequential processing, without copying the data to parallel workers
big_m <- foreach(i=1L:2L, .combine=c) %:% foreach(j=1L:2L, .combine=list) %do% {
  as.big.matrix(m[,,i,j], type="double")
}

descriptors <- lapply(big_m, describe)

# specify .noexport to avoid copying the data to each worker
foreach(m_slice_desc=descriptors, .packages=c("bigmemory"), .noexport=ls(all.names=TRUE)) %dopar% {
  # you could even modify the slices in parallel if you wanted
  m_slice <- attach.big.matrix(m_slice_desc)
  for (i in 1L:2L) {
    for (j in 1L:2L) {
      m_slice[i,j] <- m_slice[i,j] * 2
    }
  }
  # return nothing
  NULL
}

# just to show that the values were modified in place
for (bm in big_m) { print(bm[,]) }
     [,1] [,2]
[1,]    2    6
[2,]    4    8
     [,1] [,2]
[1,]   18   22
[2,]   20   24
     [,1] [,2]
[1,]   10   14
[2,]   12   16
     [,1] [,2]
[1,]   26   30
[2,]   28   32

如果您不能/不会使用bigmemory,或者如果处理每个 2 维切片太快(是的,这可能对多处理有问题,请参阅此答案),也许您可​​以从您的数据中提取 3 维切片并用于.noexport一次只复制一个,例如:

slices_3d <- lapply(1L:2L, function(i) { m[,,,i] })
foreach(slice_3d=slices_3d, .noexport=ls(all.names=TRUE)) %dopar% {
  for (j in 1L:2L) {
    slice_2d <- slice_3d[,,j]
    # do something
  }
  # return nothing
  NULL
}

我实际上不是 100% 确定上述内容会阻止复制整个文件slices_3d,如果不是,您可能必须在主 R 进程中手动提取块中的子集(例如slices_3d[1L:num_parallel_workers],每次等等),并确保只有一个块是在每次调用中导出到foreach.

于 2018-10-11T22:02:07.143 回答