Python多进程生成测试数据超百万条后性能骤降排查求助
优化高量测试数据生成中fake_workers创建的性能瓶颈
一、核心瓶颈定位
1. 内存过载
5000万条对象全塞进列表,会占用巨量内存(假设每个对象占100字节,就是5GB),一旦超出物理内存,系统触发页交换(Swap),速度直接跌到磁盘IO级别,这就是tqdm迭代速度骤降的核心原因。
2. 序列化/IPC开销
如果用multiprocessing异步池时,你是先在主进程创建全量fake_workers再传给子进程,会触发大量对象的pickle序列化/反序列化,IPC开销随数据量指数级上升。
3. 对象创建冗余
比如每次生成fake_worker都重复初始化Faker(如果用了这个库),或者重复生成相同基础数据,没有复用资源。
二、针对性优化方案
1. 用生成器+分块处理替代全量列表
别一次性把所有对象存进内存,改用生成器按需创建,分块交给子进程处理:
from multiprocessing import Pool from faker import Faker import tqdm def create_fake_worker(_): # 子进程内只初始化一次Faker,避免重复开销 fake = Faker() return { "id": fake.uuid4(), "name": fake.name(), "email": fake.email(), # 其他字段按需添加 } def generate_workers(total_count, chunk_size=10000): with Pool() as pool: # 用生成器迭代,内存只存当前chunk的数据 for chunk in tqdm.tqdm( (pool.map(create_fake_worker, range(chunk_size)) for _ in range(total_count // chunk_size)), total=total_count//chunk_size ): yield from chunk # 处理剩余不足chunk_size的部分 remaining = total_count % chunk_size if remaining > 0: yield from pool.map(create_fake_worker, range(remaining)) # 使用时直接迭代生成器,不用存全量数据 for worker in generate_workers(50000000): # 写入文件/数据库等操作 pass
- 优势:内存占用始终控制在chunk_size级别,彻底避免页交换;子进程内部复用Faker资源。
2. 全局复用Faker实例
通过进程池的初始化函数,让每个子进程只初始化一次Faker,避免重复加载本地化数据:
# 子进程全局变量,初始化一次复用 fake = None def init_worker(): global fake fake = Faker() def create_fake_worker(_): return { "id": fake.uuid4(), "name": fake.name(), "email": fake.email(), } def generate_workers(total_count, chunk_size=10000): with Pool(initializer=init_worker) as pool: # 分块处理逻辑同上 ...
3. 避免不必要的类封装
如果fake_workers只是生成结构化数据,直接用字典甚至元组,不要用自定义类——自定义类的pickle开销和内存占用都远高于基础数据类型。
4. 改用进程内批量生成
如果CPU不是瓶颈,单个进程内批量生成数据可以减少IPC开销:
def batch_create_workers(batch_size): fake = Faker() return [{"id": fake.uuid4(), "name": fake.name()} for _ in range(batch_size)] # 批量生成+处理,减少进程通信次数 for _ in tqdm.tqdm(range(50000000 // 10000)): batch = batch_create_workers(10000) # 写入文件/数据库等操作
5. 用元组降内存
如果生成的数据不需要修改,用元组代替字典,能减少约30%的内存占用:
def create_fake_worker(_): return (fake.uuid4(), fake.name(), fake.email())
三、效果验证
先测1000万条数据,用htop或psutil看内存占用,稳定在几百MB级别说明内存瓶颈解决;再看tqdm迭代速度,应该能回到接近100万条时的水平,甚至更快(减少了GC开销)。
内容的提问来源于stack exchange,提问作者greenpotlin
相关产品推荐
相关产品推荐

