将26万份CSV数据集导入R时电脑冻结,求排查代码问题
批量导入CSV数据集时电脑冻结问题排查
我尝试用以下代码批量导入260,000份CSV格式数据集(单份189KB,总大小46.6GB)到RStudio,代码来自我的研究项目脚本《LASSO code (Version for Antony)》:
# 一次性加载所有必要包 library_list <- c(library(plyr),library(dplyr),library(tidyverse), library(readr),library(stringi),library(purrr), library(stats),library(leaps),library(lars), library(elasticnet),library(data.table),library(parallel), library(microbenchmark)) # 创建数据集文件夹中所有文件的字符列表 folderpath <- "C:/Users/Spencer/Documents/EER Project/datasets folder" filepaths_list <- list.files(path = folderpath, full.names = TRUE, recursive = TRUE) # 重命名CSV数据集 DS_names_list <- basename(filepaths_list) DS_names_list <- tools::file_path_sans_ext(DS_names_list) # 对文件名列表进行排序,确保顺序正确 my_order = DS_names_list |> # 拆分数字并转为数值型 strsplit(split = "-", fixed = TRUE) |> unlist() |> as.numeric() |> # 转为数据框 matrix(nrow = length(DS_names_list), byrow = TRUE) |> as.data.frame() |> # 获取排序规则 do.call(order, args = _) DS_names_list = DS_names_list[my_order] filepaths_list = filepaths_list[my_order] # 读取所有CSV文件中的数据 CL1 <- makeCluster(detectCores() - 1L) clusterExport(CL1, c('filepaths_list')) system.time( datasets <- parLapply(CL1, filepaths_list, fread) ) stopCluster(CL1)
根据之前1000份数据集的测试,预计耗时约36小时,但运行25小时后电脑完全冻结。我的笔记本配置是11代Intel(R) Core(TM) i5-1155G7 @ 2.50GHz处理器、32GB内存、1TB SSD,硬件应该能支撑。此前我用以下代码运行56小时都没冻结:
CL <- makeCluster(detectCores() - 1L) clusterExport(CL, c('filepaths_list')) system.time( datasets <- lapply(filepaths_list, read.csv) )
后来发现应该用parLapply(CL, filepaths_list, read.csv)或read_csv就终止了操作。现在想问问上述代码有没有语法错误?
语法错误排查
- 包加载逻辑错误:
library_list <- c(library(plyr),...)写法无效。library()函数返回的是加载成功与否的逻辑值,将这些值存入向量没有实际意义,属于冗余代码。正确的批量加载包方式应该是:required_packages <- c("plyr","dplyr","tidyverse","readr","stringi","purrr", "stats","leaps","lars","elasticnet","data.table","parallel","microbenchmark") lapply(required_packages, library, character.only = TRUE) - 并行读取的依赖缺失:使用
parLapply调用fread时,未在集群节点加载data.table包。clusterExport仅传递了filepaths_list,但集群节点默认未加载data.table,会导致函数调用失败(你这里表现为冻结而非报错,可能是其他因素叠加,但这是明确的逻辑漏洞)。 - 排序逻辑的潜在风险:
strsplit后直接unlist再转矩阵的写法,仅在所有文件名拆分后元素数量完全一致时有效。如果存在文件名拆分后长度不同的情况,矩阵转换会直接报错。
冻结原因推测(非语法错误但影响稳定性)
- 内存耗尽:CSV文本读入内存后会膨胀,260,000份数据全部加载会远超过46.6GB,32GB内存被占满后系统会频繁调用虚拟内存,最终导致冻结。单线程
read.csv读取时内存增长缓慢,系统有时间处理,而并行读取会快速填满内存。 - 资源过载竞争:使用
detectCores()-1个线程(你的CPU为4核8线程,即7个线程)同时读取文件,磁盘IO成为瓶颈,CPU和内存长时间满负载运行,引发系统不稳定。
优化建议
- 修复并行读取逻辑:
# 正确加载包 required_packages <- c("plyr","dplyr","tidyverse","readr","stringi","purrr", "stats","leaps","lars","elasticnet","data.table","parallel","microbenchmark") lapply(required_packages, library, character.only = TRUE) # 并行读取时在集群节点加载data.table CL1 <- makeCluster(detectCores() - 2L) # 减少线程数降低负载 clusterExport(CL1, c('filepaths_list')) clusterEvalQ(CL1, library(data.table)) # 新增加载依赖 system.time( datasets <- parLapply(CL1, filepaths_list, fread) ) stopCluster(CL1) - 避免全量加载:如果后续是批量处理而非需要所有数据在内存,采用分批次读取处理的方式,处理完一批后释放对应内存。
- 降低并行线程数:比如使用
detectCores()/2个线程,减少磁盘IO和CPU竞争,提升系统稳定性。 - 实时监控内存:运行时用
memory.size()(Windows)或memory_usage()(Linux/macOS)监控内存变化,确认是否因内存耗尽导致冻结。
内容的提问来源于stack exchange,提问作者Marlen
相关产品推荐
相关产品推荐

