You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何读取多文件数据远慢于单文件?R语言读取优化求助

R中多CSV文件读取性能优化问题

问题背景

我需要频繁在R中读取一个大型数据集:约70万行、129列,数据被拆分成258个格式一致、大小10-24000KB的独立文件。测试发现合并为单个.csv文件后读取速度远快于多文件:

  • 使用readr时,多文件读取耗时是单文件的5倍以上
  • 改用fread后,多文件读取仍显著慢于单文件

由于无法改变文件拆分状态,且Windows下用CMD copy合并文件速度也慢,特询问:

  1. 多文件读取更慢的原因?
  2. 有无方法让多文件读取速度接近单文件?是否与磁盘硬件特性有关?

测试代码及结果

readr测试代码与结果

library(readr)
library(microbenchmark)

multiple = function() { #按原始方式读取258个文件
  lapply(multiple_filepaths, 
       function(x)
         read_csv(x, show_col_types = FALSE, progress = FALSE, col_types = coltypes))
}

single = function() { #读取合并后的单个文件
  read_csv(single_filepath,
           show_col_types = FALSE, progress = FALSE, col_types = coltypes)
}

microbenchmark(multiple(), single(), times = 10)

测试结果:

Unit: seconds
       expr       min        lq      mean    median        uq       max neval
 multiple() 40.811196 40.988007 41.330675 41.279320 41.665536 41.948959    10
   single()  5.258331  5.401542  6.016591  5.749491  6.668737  6.947849    10

fread测试结果

Unit: seconds
            expr       min        lq      mean    median        uq       max neval
      multiple() 40.972344 41.136988 41.319579 41.301631 41.493197 41.684763     3
        single()  6.224543  6.487988  6.993778  6.751433  7.378395  8.005358     3
 multiplefread()  19.16834  19.23708  19.33322  19.30583  19.41566  19.52543     3
   singlefread()  2.195246  3.631488  5.053056  5.067730  6.481960  7.896188     3

问题解答

1. 多文件读取更慢的核心原因

  • 磁盘IO开销:每个文件读取都需要触发一次磁盘打开、定位、读取、关闭流程,258个文件就会产生258次这类操作,而单文件仅需一次。磁盘寻道时间(机械盘尤为突出)和文件系统元数据查询的开销会被大幅放大。
  • 重复初始化开销:每次读取小文件时,解析器都要重复初始化列类型检测(即便指定了col_types仍有少量开销)、小批量内存分配等操作,累积起来远大于一次性处理大文件的开销。
  • 系统调用成本:每次文件读取都会涉及操作系统的系统调用,多次调用的上下文切换成本不可忽视。

2. 优化多文件读取速度的方法

(1)并行化读取

利用R的并行计算包,将文件读取任务分配到多个CPU核心,抵消单线程读取的等待时间。示例代码:

library(data.table)
library(parallel)

# 创建并行集群(保留1个核心给系统)
cl <- makeCluster(detectCores() - 1)
# 导出必要变量到集群环境
clusterExport(cl, c("multiple_filepaths", "coltypes"))
# 并行读取文件
file_list <- parLapply(cl, multiple_filepaths, function(x) {
  fread(x, colClasses = coltypes)
})
# 停止集群
stopCluster(cl)
# 合并数据
combined_data <- rbindlist(file_list)

注意:并行化对机械硬盘提升有限(磁盘IO是瓶颈),但对SSD会有明显效果。

(2)预合并为二进制格式(离线处理)

虽然无法改变原始文件拆分状态,但可以在第一次读取后将合并的数据保存为二进制格式(如.rds、.fst或.parquet),后续直接读取该二进制文件即可:

# 第一次读取并保存
library(data.table)
library(fst)

data_list <- lapply(multiple_filepaths, fread, colClasses = coltypes)
combined_data <- rbindlist(data_list)
write_fst(combined_data, "combined_data.fst")

# 后续直接读取
combined_data <- read_fst("combined_data.fst")

二进制格式读取速度远快于CSV,且只需一次合并操作,后续可反复复用。

(3)优化磁盘硬件

  • 替换为SSD:SSD的随机读取性能远高于机械盘,能大幅降低多文件读取的寻道时间开销,这也是你当前多文件读取耗时高的核心因素之一。
  • 优化文件系统:Windows下可开启NTFS压缩(CSV这类文本文件压缩率高,读取时解压开销远小于IO节省),或使用更高效的文件系统。

(4)减少读取额外开销

  • 确保col_types/colClasses参数完全准确,避免解析器做类型推断;
  • 关闭进度条、类型提示等额外输出;
  • 优先使用data.table::fread,从测试结果看,它的多文件读取速度已是readr::read_csv的2倍左右,底层实现更高效。

内容的提问来源于stack exchange,提问作者Richard Berry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:15:53