Python多进程程序仅2个子进程占用CPU的问题排查求助
问题分析与解决方案
看起来你遇到的核心问题是进程池里的大部分任务根本没被提交,导致98个进程全程闲置。让我拆解一下代码里的问题,再给你修正后的版本:
为什么大部分进程资源占用为0?
你的代码有三个关键问题:
任务拆分逻辑完全失效
你写的for i in range(0, 1)只循环一次,加上input_files.append(os.listdir(file_path))让input_files变成了一个包含单个文件列表的二维数组。最终targetLists里只会有一个元素——也就是所有文件的完整列表。进程池只收到了这一个任务,自然只有一个子进程在干活,剩下99个进程全程闲置,资源占用当然是0。参数传递的隐形错误
在pool.apply_async(start_scan, args=(x))里,args需要是一个元组,但你写的(x)只是把x本身传进去,不是元组。如果x是列表,Python会把列表的每个元素当作单独参数传给start_scan,但你的start_scan只接受一个files参数,这会触发TypeError——可能你没注意到这个错误,或者被异常捕获吞掉了。单任务内部串行处理
就算任务拆分正确,start_scan里是逐个循环处理文件,每个scan调用都是串行执行的,根本没利用进程池的并行能力。
修正后的代码示例
我重新整理了代码,简化了逻辑,让进程池真正并行起来:
import multiprocessing as mp import os import time import traceback import logging # 假设你的logger已经初始化完成 logger = logging.getLogger(__name__) def scan(file_path): # 这里保留你原有的scan实现 pass def process_single_file(filedata): """单个文件的独立处理逻辑,交给进程池并行执行""" try: start = time.time() full_path = os.path.join('/home/something/test/', filedata) scan_result = scan(full_path) # 写入结果,建议用with保证文件正确关闭 with open('result_clean.csv', 'a') as f: f.write(f"Result {scan_result} for file {filedata}\n") end = time.time() logger.info(f'File {filedata} processed in {end - start:.2f}s') return scan_result except Exception as e: logger.error(f'Failed to process {filedata}: {str(e)}') return None def clean_(self, worker=100): # 创建进程池,worker数量建议不超过CPU核心数的2倍,避免上下文切换开销 pool = mp.Pool(processes=worker) start_total = time.time() file_path = self.folder_clean_scan all_files = os.listdir(file_path) # 直接获取文件列表,不是二维数组 # 用pool.map自动分配任务到进程池,每个文件对应一个任务 try: all_results = pool.map(process_single_file, all_files) print(f"Processing complete. Results: {all_results}") except Exception as e: traceback.print_exc() finally: # 必须关闭进程池并等待所有进程完成 pool.close() pool.join() end_total = time.time() print(f"Total processing time: {end_total - start_total:.2f}s")
关键改进点
- 真正的并行处理:用
pool.map把每个文件的处理任务分发到进程池,每个进程会处理一个或多个文件,充分利用所有进程资源。 - 简化任务拆分:不需要手动拆分文件列表,
pool.map会自动完成任务分配,避免了原代码中复杂且错误的拆分逻辑。 - 修正参数传递:
map会自动把all_files的每个元素作为参数传给process_single_file,避免了元组传递的错误。 - 资源安全:添加
pool.close()和pool.join(),确保所有进程完成后再结束主进程,避免资源泄漏。
这样修改后,你的进程池里的进程都会被利用起来(实际并行数受限于CPU核心数,但不会出现98个进程完全闲置的情况),CPU和内存占用会更符合你的预期。
内容的提问来源于stack exchange,提问作者SaiKiran
相关产品推荐
相关产品推荐

