我正在R中使用doMPI来并行保存netCDF气候数据。该数据以4维矩阵m
的形式存储在R中,其中在经度和纬度网格上具有20000个时间点的6个变量的数据。 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
矩阵复制到每个工作人员。那占用了过多的内存,我需要减少复制的数据量。我对from this answer的想法是,我可以遍历矩阵的每个时间片,因此在每次迭代时仅将时间片的数据复制到每个工人。 foreach
构造允许多个对象同时进行迭代,因此我什至可以将时间索引与矩阵时间片并排使用,而不会出现问题。不幸的是,我不知道通过时间片对矩阵进行迭代的任何方法。有没有办法做到这一点,使得在变量t
的{{1}}循环的每次迭代foreach
上,我可以拥有一个变量var
,该变量保存二维矩阵data
?
我已经在下面尝试了直观的方法,但是它遍历每个单独的元素,而不是一次遍历整个时间片。
m[,,t,var]
答案 0 :(得分:0)
如果您可以在主R流程中处理数据,
您可以尝试将每个二维切片从big.matrix
包转换成bigmemory
,
并在您的并行工作者中使用它。
仅在处理从属进程中的每个切片所需的时间很长时,这才有用。
参见此示例,请注意,您可以使用foreach
嵌套2个%:%
循环
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
,
或者处理每个二维切片的速度过快
(是的,这对于多处理可能是有问题的,
参见this answer),
也许您可以从数据中提取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
时只导出一个块。