Python大文件多进程处理:如何规避内存超限问题?
处理大文件的Python多进程优化方案
问题描述
我有一个几GB到几十GB的大数据文件,希望用Python通过多进程进行读取和处理。当前做法是将文件分块(比如100MB),并将这些块传递给进程,代码如下:
from multiprocessing import Pool with Pool(processes=8) as pool: file_chunk = readFileInJunks() #iterator for i in range(8): pool.apply_async(f, (next(file_chunk),)) pool.close() pool.join()
但当文件大小超过内存时,这种方法会触发内存限制。我的疑问是:如何避免触发内存限制?
我可以让每个进程自行加载数据块,但这会导致n个进程同时访问同一文件,可能会降低读取速度(尤其是老旧磁盘)。另一种选择是在进程池有空位时手动调用apply_async,但这在某种程度上失去了进程池的意义。有没有更优雅的处理方式?
解决方案:用Pool.imap/imap_unordered配合生成器实现懒加载
核心思路
利用生成器逐块读取文件(避免一次性加载整个文件到内存),结合进程池的imap或imap_unordered方法,让进程池自动从生成器中获取空闲进程所需的数据块,无需手动管理任务提交,同时保证只有主进程负责文件读取,避免多进程磁盘IO竞争。
代码示例
1. 二进制文件处理
from multiprocessing import Pool def process_chunk(chunk): # 替换为你的实际数据处理逻辑 # 比如解析二进制数据、计算统计值等 return len(chunk) def read_binary_chunks(file_path, chunk_size=100*1024*1024): """生成器:逐块读取二进制文件,避免内存溢出""" with open(file_path, 'rb') as f: while chunk := f.read(chunk_size): yield chunk if __name__ == '__main__': # 初始化8进程池 with Pool(processes=8) as pool: # imap会自动将生成器的块分配给空闲进程,懒加载不占内存 for result in pool.imap(process_chunk, read_binary_chunks('large_data.bin')): # 可选:处理每个块的结果,不需要可忽略 print(f"处理完成一个块,结果:{result}")
2. 文本文件处理(保证行完整)
如果是文本文件,需要避免将一行拆分为两个块,可调整生成器逻辑:
def read_text_chunks(file_path, chunk_size=100*1024*1024): """生成器:按块读取文本文件,保证每个块包含完整的行""" with open(file_path, 'r', encoding='utf-8') as f: buffer = '' while True: chunk = f.read(chunk_size) if not chunk: if buffer: yield buffer break # 找到最后一个换行符,拆分块与缓冲区 last_newline = chunk.rfind('\n') if last_newline == -1: buffer += chunk else: yield buffer + chunk[:last_newline+1] buffer = chunk[last_newline+1:] # 后续处理逻辑同二进制文件,替换read_binary_chunks为read_text_chunks即可
优势说明
- 内存友好:生成器每次仅读取一个块到内存,不会加载整个文件,彻底避免内存溢出。
- 进程池自动调度:
imap/imap_unordered会自动将数据块分配给空闲进程,无需手动调用apply_async,完全发挥进程池的管理优势。 - 磁盘IO优化:只有主进程负责文件读取,子进程仅处理数据,避免多进程同时读文件的IO竞争,尤其适合老旧机械硬盘。
- 可选顺序控制:需要保持处理结果与文件顺序一致时用
imap,不需要顺序时用imap_unordered,后者效率更高。
内容的提问来源于stack exchange,提问作者Regedit
相关产品推荐
相关产品推荐

