Python合并多份CSV文件耗时过长(含解压),如何优化代码降低处理时长?
Python多CSV合并流程优化方案
现有代码核心性能瓶颈
- 线程池不适用于CPU密集场景:pandas读写CSV、数据合并属于CPU密集操作,Python线程受GIL全局解释器锁限制无法并行计算,多线程反而会增加调度开销
- 解压环节冗余:提前将所有zip全量解压到磁盘,产生大量不必要的磁盘IO开销
- 读写CSV参数无优化:默认
pd.read_csv会自动推断列类型、加载全部列,pd.to_csv默认写入索引,都会产生冗余计算 - 全量加载合并内存压力大:一次性读取所有CSV文件到内存再拼接,数据量大时会触发系统内存交换,大幅降低处理速度
具体优化方案
1. 替换多线程为多进程
将ThreadPoolExecutor更换为ProcessPoolExecutor,避开GIL限制,充分利用多核CPU性能,并行处理多个zip文件。
2. 直接读取zip内的CSV文件,跳过磁盘解压步骤
无需提前将zip解压到本地磁盘,直接从压缩包内读取CSV内容,完全省去解压环节的3分钟耗时,同时减少大量小文件IO开销。示例代码:
def process_zip(zip_path): dfs = [] with zipfile.ZipFile(zip_path, 'r') as zf: # 遍历压缩包内所有csv文件 for csv_name in [f for f in zf.namelist() if f.endswith('.csv')]: with zf.open(csv_name) as f: df = pd.read_csv(f, **read_kwargs) dfs.append(df) combined_df = pd.concat(dfs, ignore_index=True) # 后续保存逻辑
3. 优化CSV读写参数
读CSV时添加参数减少冗余计算:
- 显式指定
dtype参数,避免pandas自动推断列类型的开销 - 用
usecols指定需要加载的列,过滤不需要的冗余数据 - 添加
low_memory=False关闭分块类型推断,避免额外计算
read_kwargs = { "encoding": "cp932", "dtype": {"列名1": str, "列名2": int, "列名3": float}, # 按实际业务调整 "usecols": ["需要保留的列1", "需要保留的列2"], # 不需要的列直接过滤 "low_memory": False }
写CSV时关闭索引写入,减少数据量:
combined_df.to_csv(save_path, encoding='cp932', index=False)
4. 迭代合并降低内存压力
如果单个zip内CSV数量极多,不要一次性读取所有文件再拼接,采用迭代方式逐文件合并,避免内存溢出和交换:
combined_df = pd.DataFrame() with zipfile.ZipFile(zip_path, 'r') as zf: for csv_name in [f for f in zf.namelist() if f.endswith('.csv')]: with zf.open(csv_name) as f: df = pd.read_csv(f, **read_kwargs) combined_df = pd.concat([combined_df, df], ignore_index=True)
5. 极端大文件场景用高性能库替代pandas
如果数据量超过10G,推荐使用polars库替代pandas,默认自带并行优化,读写CSV速度是pandas的3~10倍,内存占用更低:
import polars as pl # 读zip内CSV with zipfile.ZipFile(zip_path, 'r') as zf: dfs = [pl.read_csv(zf.open(csv_name), encoding='cp932') for csv_name in [f for f in zf.namelist() if f.endswith('.csv')]] combined_df = pl.concat(dfs) # 写CSV combined_df.write_csv(save_path, encoding='cp932')
优化后预期效果
- 解压环节耗时从3分钟降至接近0
- 合并环节耗时可降低70%90%,原17分钟可压缩至25分钟区间
- 内存占用可降低30%以上,避免内存交换开销
内容的提问来源于stack exchange,提问作者rin
相关产品推荐
相关产品推荐

