Python多进程性能优化及数据存储相关技术问询
项目流程
- 将Python自定义类保存为pickle文件
- 在多进程中加载pickle文件
- 将加载后的文件输入至机器学习模型
代码实现
def get_learning_data(file): print(file) picklefile = open(file, 'rb') processed_data = pickle.load(picklefile) picklefile.close() print(f'end with file {file}') if __name__ == '__main__': # files file_list = [r'sample{0}.pickle'.format(i) for i in range(100)] _start = time() file_count = len(file_list) print(multiprocessing.cpu_count()) MAX_PROCESS = 12 d = file_count // MAX_PROCESS if file_count % MAX_PROCESS == 0 else file_count // MAX_PROCESS +1 file_batch = [file_list[i * MAX_PROCESS : (i + 1) * MAX_PROCESS] for i in range(d)] with multiprocessing.Pool(MAX_PROCESS) as pool: for files in file_batch: pool.map( get_learning_data, files ) print(f'multi done time : {time() - _start}') _start = time() for f in file_list: get_learning_data(f) print(f'single done time : {time() - _start}')
问题咨询
multiprocessing.cpu_count()返回值为20,与处理器数量一致而非核心数,请问最优进程数设为12还是20?- 因Python GIL问题采用多进程,是否有其他替代方案?
- 测试100个文件时,10进程耗时67秒,单进程耗时183秒,性能提升幅度低于预期;同事用30核CPU测试时多进程耗时反而更长,原因是什么?
- 除XML、pickle、JSON外,是否有其他方式保存Python dataclass?
问题解答
1. 最优进程数选择
优先实际测试20进程的表现,你的任务属于IO密集型(加载文件),理论上IO密集型任务可以开比逻辑核心数更多的进程,但实际受限于磁盘IO带宽:
- 如果是SSD磁盘,并行读写能力强,20进程可能比12进程更快;如果是机械硬盘,多进程同时读会触发大量随机IO,反而因为等待IO导致上下文切换开销增加,此时12进程可能更稳定。
- 另外
multiprocessing.cpu_count()返回的是逻辑核心数(含超线程),不是物理处理器数量,你看到的“20”应该是逻辑核心数。建议直接跑20进程的测试,对比12进程的耗时,选实际更快的配置。
2. GIL问题的替代方案
针对你的IO密集型场景,有这些更合适的替代方案:
- 线程池:用
concurrent.futures.ThreadPoolExecutor,IO等待时GIL会自动释放,线程的创建和调度开销远低于进程,对IO密集型任务效率更高。 - 异步IO:用
asyncio配合aiofiles异步读取文件,适合高并发IO场景,能在单线程内处理大量IO任务。 - 其他Python实现:比如PyPy(对IO和数值计算都有优化)、Cython(编译核心代码绕开GIL),如果后续有计算密集型任务可以考虑。
3. 性能提升不达预期/多进程变慢的原因
核心问题出在磁盘IO瓶颈和进程开销:
- 磁盘IO竞争:当多个进程同时读取文件,磁盘的读写带宽被占满,所有进程都进入等待状态,尤其是机械硬盘,随机读写性能差,多进程并行反而不如单进程顺序读高效。同事的30核CPU如果搭配的磁盘性能一般,30进程同时读会让IO竞争更激烈,耗时自然更长。
- 进程调度开销:如果单个pickle文件很小,加载耗时短,那么进程的启动、调度开销占比会变大,抵消并行带来的收益。
- 手动分批的问题:你代码里手动把文件分成批次,可能导致任务分配不均,部分进程提前结束,浪费资源,直接用
pool.map处理整个file_list即可,让进程池自动调度任务。
4. Python dataclass的其他保存方式
除了XML、pickle、JSON,还有这些实用选项:
- MsgPack:二进制序列化格式,体积比JSON小,速度快,支持大部分Python数据类型,把dataclass转成字典后就能直接序列化。
- YAML:可读性极强,支持复杂嵌套结构,适合配置类dataclass,用
pyyaml库即可实现序列化/反序列化。 - SQLite/关系型数据库:如果需要持久化查询,用
sqlalchemy或dataclasses-sqlalchemy把dataclass映射到数据库表,方便数据管理。 - HDF5:适合大数据量的数值型dataclass,用
h5py库,支持高效读写和压缩,适合机器学习场景的批量数据存储。 - Protocol Buffers:谷歌的二进制序列化格式,需要定义.proto文件,适合跨语言交互,能和dataclass快速互转。
- Toml:简洁的配置格式,Python 3.11+内置
tomllib库,适合小型配置类dataclass。
内容的提问来源于stack exchange,提问作者ding lee
相关产品推荐
相关产品推荐

