如何在R的foreach并行循环中返回两个完整更新后的列表?
问题分析
你的核心问题在于并行循环的内存独立性:foreach的每个并行worker进程都拥有独立的内存空间,主环境中的list_1和list_2不会被worker直接修改。当前代码中,每个worker拿到的是初始列表的副本,修改第i个位置后返回整个副本,最终test是10个仅填充了对应i位置的列表集合,而非合并后的完整列表。
解决方案
我们需要调整逻辑:让每个并行迭代只返回当前i对应的两个数据框,之后再将所有迭代的结果合并为完整的list_1和list_2。以下是两种可行写法:
写法一:在foreach中直接合并(自定义combine函数)
library(foreach) library(doParallel) library(doSNOW) list_1 <- list(partition = as.list(rep(NA, 10))) for(h in 1:1){ list_2 <- as.list(rep(NA, 10)) cl <- parallel::makeCluster(4) registerDoSNOW(cl) iteration_progress <- function(n){cat(sprintf("Task %d out of %d completed\n", n, 10))} test <- foreach(i = 1:10, .packages = c("dplyr"), .options.snow = list(progress = iteration_progress), .errorhandling = "pass", .combine = function(...) { # 收集所有迭代的返回结果 iter_results <- list(...) # 构建完整的list_1(partition结构) full_list1 <- list(partition = lapply(1:10, function(idx) iter_results[[idx]]$part1)) # 构建完整的list_2 full_list2 <- lapply(1:10, function(idx) iter_results[[idx]]$part2) # 返回包含两个完整列表的结果 return(list(full_list1, full_list2)) }) %dopar% { # 仅生成当前i对应的两个数据框,不修改全局列表 df1 <- data.frame(a = runif(5, min = 1, max = 100), b = runif(5, min = 1, max = 100)) df2 <- data.frame(a = runif(5, min = 1, max = 100), b = runif(5, min = 1, max = 100)) # 返回当前迭代的两个结果 list(part1 = df1, part2 = df2) } parallel::stopCluster(cl) # 按你的需求提取两个列表 output_list_1 <- test[[1]] output_list_2 <- test[[2]] }
写法二:先收集所有迭代结果,再手动合并(更直观)
library(foreach) library(doParallel) library(doSNOW) list_1 <- list(partition = as.list(rep(NA, 10))) for(h in 1:1){ list_2 <- as.list(rep(NA, 10)) cl <- parallel::makeCluster(4) registerDoSNOW(cl) iteration_progress <- function(n){cat(sprintf("Task %d out of %d completed\n", n, 10))} # 先收集每个迭代的两个数据框 test <- foreach(i = 1:10, .packages = c("dplyr"), .options.snow = list(progress = iteration_progress), .errorhandling = "pass") %dopar% { df1 <- data.frame(a = runif(5, min = 1, max = 100), b = runif(5, min = 1, max = 100)) df2 <- data.frame(a = runif(5, min = 1, max = 100), b = runif(5, min = 1, max = 100)) list(df1, df2) } parallel::stopCluster(cl) # 手动合并为完整列表 output_list_1 <- list(partition = lapply(test, function(x) x[[1]])) output_list_2 <- lapply(test, function(x) x[[2]]) }
验证结果
两种写法最终都能得到和普通for循环一致的完整列表,且可以通过output_list_1 <- test[[1]](写法一)或直接使用合并后的变量(写法二)提取结果。
内容的提问来源于stack exchange,提问作者Marine
相关产品推荐
相关产品推荐

