并行场景下是否需根据工作进程数调整terra的memfrac参数?
问题描述
使用future/future.apply包运行terra代码时遭遇内存错误:Error in eval(expr, p) : std::bad_alloc。当前配置为:
- 并行计划采用
future包的"multisession"策略,工作进程数为4 terra的memfrac参数保留默认值0.6
疑问:
- 是否需要根据工作进程数调整
memfrac参数? future.callr::callr并行计划是否适用于该场景?该计划下memfrac参数如何处理?
示例代码:
library(terra) #> terra 1.7.78 library(future.apply) #> Loading required package: future library(stringr) # 坡度计算函数 slopefun<- function(x){ fn<- paste0(str_remove(x, "\\.tif$"),"_slope.tif") terrain(rast(x), v="slope", filename=fn, overwrite=TRUE) return(fn) } # 创建数据集 r<- rast(volcano, extent= ext(2667400, 2667400 + ncol(volcano)*10, 6478700, 6478700 + nrow(volcano)*10), crs = "EPSG:27200") # 文件名列表 r_list<- list("test1.tif", "test2.tif", "test3.tif", "test4.tif") # 将数据写入对应文件 writeRaster(r, filename = r_list[[1]], overwrite=TRUE) writeRaster(r*2, filename = r_list[[2]], overwrite=TRUE) writeRaster(r*3, filename = r_list[[3]], overwrite=TRUE) writeRaster(r*4, filename = r_list[[4]], overwrite=TRUE) nworkers<- 4 plan(strategy = "multisession", workers= nworkers) # 配置并行环境 res_list<- future_lapply(r_list, FUN = slopefun) plan(strategy = "sequential") # 结果大于1,是否需要除以工作进程数? # 例如在本场景中,因有4个工作进程,是否需将memfrac降至0.25或更低? terraOptions()$memfrac*nworkers #> memfrac : 0.6 #> tolerance : 0.1 #> verbose : FALSE #> todisk : FALSE #> tempdir : C:/Users/socce/AppData/Local/Temp/Rtmp2puqqO #> datatype : FLT4S #> memmin : 1 #> progress : 3 #> [1] 2.4
解答
1. 必须根据工作进程数调整memfrac参数
terra的memfrac参数定义的是单个R进程可使用的系统内存比例,而非总内存的比例。在multisession并行模式下,每个工作进程都是独立的R实例,会各自按照memfrac设定的比例占用内存。
以你的场景为例,4个工作进程×0.6的内存比例=2.4,意味着所有进程尝试占用的内存总量是系统总内存的2.4倍,远超实际可用内存,这正是触发std::bad_alloc内存错误的核心原因。
调整建议:
- 直接将
memfrac设置为1/工作进程数左右,比如4个进程时设为0.2(比0.25略低,预留缓冲空间) - 执行调整代码:
terraOptions(memfrac = 0.2) - 如果仍出现内存问题,可进一步降低该值,或减少工作进程数
2. future.callr::callr计划的适用性及memfrac处理
适用性
callr并行计划会为每个任务启动一个独立的、完全隔离的R进程,与multisession类似,但进程管理更严谨,能避免部分进程间的资源冲突或内存泄漏问题。如果multisession模式下的内存问题伴随进程间干扰,callr计划会是更稳定的替代方案,完全适用于你的坡度计算场景。
memfrac处理逻辑
callr计划下,每个独立R进程仍会遵循terra的memfrac参数设置,因此同样需要根据工作进程数调整memfrac值,原理和multisession一致,避免总内存占用过载。
额外优化:callr支持通过rlimits参数直接限制每个进程的内存上限,比memfrac更直观。例如,限制每个进程最多使用2GB内存:
library(future.callr) plan(callr, workers = 4, rlimits = list(asize = 2e9)) # asize单位为字节 terraOptions(memfrac = 0.8) # 此时memfrac基于每个进程的内存上限计算,而非系统总内存
内容的提问来源于stack exchange,提问作者ailich
相关产品推荐
相关产品推荐

