如何捕获Python多并行子进程的运行时长与返回值
如何捕获Python多并行子进程的运行时长与返回值
别担心,这个任务一点都不难,Python完全能轻松搞定!我来给你一步步讲清楚怎么实现~
首先,你用subprocess.Popen的思路是对的,因为它是非阻塞的,可以同时启动多个子进程。核心就是给每个进程记录启动时间,等它结束后计算时长,再获取返回码就行。
方法一:手动管理子进程(基础版)
这种方式不需要额外依赖,直接用subprocess和datetime就能实现:
import subprocess import datetime # 替换成你实际要运行的命令,尽量用列表形式避免shell=True的安全风险 my_process = ["echo", "hello world"] process_count = 8 # 存储每个进程的对象和启动时间 process_info = [] # 批量启动并行子进程 for _ in range(process_count): start_time = datetime.datetime.now() proc = subprocess.Popen( my_process, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True ) process_info.append((proc, start_time)) # 等待每个进程结束,收集返回值和时长 results = [] for idx, (proc, start_time) in enumerate(process_info, 1): # 等待进程结束并获取返回码 return_code = proc.wait() # 计算结束时间和运行时长(转成微秒) end_time = datetime.datetime.now() duration_us = (end_time - start_time).total_seconds() * 1_000_000 results.append({ "process_id": idx, "return_code": return_code, "duration_us": round(duration_us, 2) }) # 打印结果 for res in results: print(f"进程{res['process_id']}: 返回码={res['return_code']}, 运行时长={res['duration_us']}微秒")
方法二:用concurrent.futures简化代码(进阶版)
如果想让代码更简洁,可以用Python标准库的concurrent.futures.ThreadPoolExecutor,它会帮你自动管理并行任务:
from concurrent.futures import ThreadPoolExecutor import subprocess import datetime def run_single_process(cmd): """封装单个进程的启动、计时和结果收集逻辑""" start_time = datetime.datetime.now() # 用subprocess.run直接等待进程结束,比Popen更简洁 result = subprocess.run( cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True ) end_time = datetime.datetime.now() duration_us = (end_time - start_time).total_seconds() * 1_000_000 return { "return_code": result.returncode, "duration_us": round(duration_us, 2) } # 准备8个要运行的命令 commands = [["echo", "hello world"] for _ in range(8)] # 并行执行所有任务 with ThreadPoolExecutor(max_workers=8) as executor: results = list(executor.map(run_single_process, commands)) # 输出结果 for idx, res in enumerate(results, 1): print(f"进程{idx}: 返回码={res['return_code']}, 运行时长={res['duration_us']}微秒")
一些小提示
- 尽量避免用
shell=True,除非你的命令必须依赖shell特性(比如管道、通配符),否则用列表形式的命令更安全,也不容易出现参数解析错误。 - 如果需要更精准的计时,可以用
time.perf_counter()替代datetime.now(),它的精度更高:import time start_time = time.perf_counter() # ...运行进程... end_time = time.perf_counter() duration_us = (end_time - start_time) * 1_000_000
完全不用担心这个任务的难度,Python的标准库已经把这些需求都覆盖啦~
备注:内容来源于stack exchange,提问作者Pax to You
相关产品推荐
相关产品推荐

