Pandas读写超3000个CSV文件后磁盘卡顿问题求助
问题描述
我正在编写脚本处理约11000个单文件小于1M的CSV文件,使用Pandas读取并修改后写入新CSV文件。在搭载慢HDD的Ubuntu设备上,每处理100个文件耗时5-10秒,iostat显示%iowait约为50%;但处理约3000个文件后,%iowait会飙升至80%以上,系统逐渐卡顿直至无响应,此时r/s下降但%iowait维持在80-90%,立即终止脚本后系统数分钟内恢复正常。
在搭载NVMe的Windows子系统Linux(WSL)上测试,处理速度更快,但保留所有Pandas功能时,处理约5000个文件后仍会冻结。
相关脚本(已移除大部分DataFrame处理逻辑):
from pathlib import Path import pandas as pd def main(): src_path = Path("/mnt/4TB/test/tmp/src") dest_path = Path("/mnt/4TB/test/tmp/dest") files = src_path.glob("**/*.txt") for file in files: df_new = pd.read_csv( file, names=['a','b','c','d','e','f','g','h'], dtype={'a': str, 'b': str}, # 移除该行脚本可执行完成 header=0, ) df_new.to_csv(dest_path / f"{file.name}") # 修正原脚本中的data_path为dest_path if __name__ == "__main__": main()
问题原因分析
- Pandas dtype指定的额外开销:显式指定
dtype={'a': str, 'b': str}时,Pandas会对每一列进行严格的类型校验和转换,每个小文件都要重复执行该逻辑,累积后大幅增加CPU和IO负载,导致系统IO队列拥堵。移除该行后脚本可正常执行完成,也验证了这一点。 - 小文件的IO特性瓶颈:HDD的随机IO性能远低于顺序IO,大量小文件的频繁读写会不断触发磁头寻道操作。随着处理文件增多,系统页缓存被占满,后续读写只能直接操作磁盘,IO等待时间剧增,
%iowait飙升。即使是NVMe,大量小文件的高频IO也会耗尽设备的IO队列深度,最终导致系统冻结。 - 同步串行处理的缺陷:脚本采用单进程串行处理,每个文件都要经历"读-处理-写"的完整流程,随着处理的文件增多,未完成的IO请求不断积压,系统资源被持续占用,最终引发卡顿。
解决建议
- 优化Pandas读写参数
- 若业务允许,移除不必要的
dtype指定,或先以object类型读取,后续再按需转换类型,减少类型校验的开销 - 读取CSV时添加
low_memory=False参数,避免Pandas分块读取时的内存类型推断开销 - 读写时指定
buffering参数(如buffering=1024*1024),增大缓冲区,减少磁盘IO的调用频次
- 若业务允许,移除不必要的
- 批量/并行处理文件
- 批量读取多个文件到内存,统一完成处理后再批量写入,降低磁盘IO的触发频率
- 使用多进程(如
multiprocessing.Pool)并行处理文件,但需控制进程数量(建议等于CPU核心数或略多),避免IO过载
- 优化磁盘IO路径
- 将源文件临时复制到内存文件系统(如Linux的
tmpfs),处理完成后再写回HDD,完全规避磁盘性能瓶颈 - 先将多个小CSV合并为大文件,用Pandas批量处理后再拆分为小文件,利用顺序IO提升效率
- 将源文件临时复制到内存文件系统(如Linux的
- 系统层面优化
- 将Linux的IO调度器切换为
deadline(适合HDD),执行命令:echo deadline | sudo tee /sys/block/sdX/queue/scheduler(替换sdX为你的HDD设备名),减少IO请求的等待时间 - 增大系统页缓存大小,减少磁盘直接读写的次数
- 将Linux的IO调度器切换为
asyncio是否可行?
asyncio对这类场景的收益有限。原因在于Pandas的read_csv和to_csv都是同步阻塞操作,原生不支持异步。若要基于asyncio实现,需使用aiofiles手动读取文件内容,再手动解析CSV(无法直接使用Pandas),这会失去Pandas便捷的数据处理能力,反而增加开发复杂度。
如果必须保留Pandas的功能,优先选择多进程或批量处理的方案,比asyncio更高效且易实现。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

