
本教程详细阐述了如何在Unix系统下,利用Python的`subprocess`模块执行外部程序,并结合`resource`和`psutil`库精确监控其CPU时间(用户态与系统态)及内存使用情况。文章重点讲解了`resource.getrusage`的正确使用时机,以避免时间测量不准确的问题,并提供了基于进程ID的内存实时采样方法,确保对子进程性能进行全面而准确的评估。
在生物信息学工具开发、系统性能测试或任何需要执行外部命令并评估其效率的场景中,精确监控子进程的资源使用至关重要。本教程将指导您如何使用Python在Unix环境下实现这一目标,重点关注CPU时间(用户态和系统态)以及内存使用。
我们将主要使用以下Python库:
resource模块提供了一个getrusage函数,可以用来获取进程及其子进程的资源使用情况。要准确测量由subprocess.Popen启动的子进程的CPU时间,关键在于getrusage的调用时机。
立即学习“Python免费学习笔记(深入)”;
resource.getrusage(resource.RUSAGE_CHILDREN)会返回所有已终止子进程所使用的资源总和。这意味着,如果您在子进程完成之前调用它来获取结束时的资源使用情况,它将不会包含当前仍在运行的子进程的数据。
常见错误: 在子进程启动后立即调用usage_end = resource.getrusage(resource.RUSAGE_CHILDREN),而子进程还在后台运行,会导致ru_utime和ru_stime显示为0,因为它只统计了在调用usage_end之前已经终止的子进程。
正确做法:
这样,最终的usage_end将包含由subprocess.Popen启动的子进程所消耗的全部CPU时间。
CPU时间类型:
import subprocess
import resource
import sys
import time
def measure_cpu_time(command_list):
"""
测量子进程的CPU时间(用户态和系统态)。
"""
print(f"Executing command: {' '.join(command_list)}")
# 1. 启动前获取资源使用情况(包括已终止的子进程,通常为0)
usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)
# 2. 启动子进程
# subprocess.DEVNULL 避免子进程输出到控制台
# subprocess.PIPE 捕获标准错误,以便在失败时打印
process = subprocess.Popen(command_list, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, encoding='utf-8')
# 3. 等待子进程完成
# process.wait() 会阻塞直到子进程终止
# 或者使用 process.poll() 循环等待,以便在循环中进行其他监控(如内存)
process.wait()
# 4. 子进程结束后获取资源使用情况
usage_end = resource.getrusage(resource.RUSAGE_CHILDREN)
# 5. 检查子进程退出码
if process.returncode != 0:
error_message = process.stderr.strip()
sys.exit(f"FAILED: {' '.join(command_list)}\n{error_message}")
# 6. 计算CPU时间
cpu_time_user = usage_end.ru_utime - usage_start.ru_utime
cpu_time_system = usage_end.ru_stime - usage_start.ru_stime
print(f"User CPU Time: {cpu_time_user:.6f} seconds")
print(f"System CPU Time: {cpu_time_system:.6f} seconds")
return cpu_time_user, cpu_time_system
if __name__ == "__main__":
# 示例:运行一个模拟耗时任务的命令
# 例如:`sleep 5` 会等待5秒,但CPU时间很低
# 更能体现CPU时间的命令可以是计算密集型任务,如 `dd if=/dev/zero of=/dev/null count=1000000 bs=1K`
# 或者一个简单的Python脚本
# command_to_run = ["sleep", "5"]
command_to_run = ["python", "-c", "import time; sum(range(10**7)); time.sleep(1); sum(range(10**7))"]
measure_cpu_time(command_to_run)psutil库提供了强大的功能来获取系统和进程的详细信息。要监控特定子进程的内存使用,我们需要获取其进程ID(PID),然后使用psutil.Process(pid)来查询该进程的内存信息。
psutil.Process(pid).memory_info()会返回一个包含多种内存指标的命名元组,其中:
为了实时监控,我们需要在子进程运行期间定期采样。
import psutil
import time
def get_process_memory_usage(pid):
"""
获取指定进程的RSS内存使用量(以GB为单位)。
"""
try:
process = psutil.Process(pid)
return process.memory_info().rss / (1024.0 ** 3) # 转换为GB
except psutil.NoSuchProcess:
# 进程可能已经结束
return 0.0
except psutil.AccessDenied:
# 权限不足,无法获取进程信息
print(f"Warning: Access denied for process {pid}. Cannot get memory info.", file=sys.stderr)
return 0.0
def monitor_memory_snapshots(process_obj, slice_in_seconds=1):
"""
实时监控并收集子进程的内存快照。
"""
memory_snapshots = []
# 循环直到子进程结束
while process_obj.poll() is None:
mem_gb = get_process_memory_usage(process_obj.pid)
if mem_gb > 0: # 只有当成功获取到内存信息时才记录
memory_snapshots.append(mem_gb)
time.sleep(slice_in_seconds)
return memory_snapshots
# 注意:此函数不能单独运行,需要与subprocess结合
# 完整的集成示例将在下一节提供重要提示: 原始问题中的get_memory_info函数调用的是psutil.virtual_memory(),这获取的是系统整体的内存使用情况,而非单个子进程。如果目标是监控子进程,务必使用psutil.Process(pid)来获取特定进程的内存信息。
现在,我们将上述方法整合到一个完整的函数中,用于全面监控子进程的性能。
import sys
import os
import subprocess
import resource
import psutil
import time
def get_process_memory_usage(pid):
"""
获取指定进程的RSS内存使用量(以GB为单位)。
"""
try:
process = psutil.Process(pid)
return process.memory_info().rss / (1024.0 ** 3) # 转换为GB
except (psutil.NoSuchProcess, psutil.AccessDenied):
return 0.0
def monitor_subprocess_performance(command_list, report_file_path="performance_report.txt", slice_in_seconds=1):
"""
监控子进程的CPU时间(用户态和系统态)及内存使用情况。
"""
print(f"Executing command: {' '.join(command_list)}")
# 1. 启动前获取资源使用情况
usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)
# 2. 启动子进程
process = subprocess.Popen(command_list, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, encoding='utf-8')
# 3. 实时监控内存使用
memory_snapshots = []
# 循环直到子进程结束
while process.poll() is None:
mem_gb = get_process_memory_usage(process.pid)
if mem_gb > 0:
memory_snapshots.append(mem_gb)
time.sleep(slice_in_seconds)
# 4. 子进程结束后获取资源使用情况
usage_end = resource.getrusage(resource.RUSAGE_CHILDREN)
# 5. 检查子进程退出码
if process.returncode != 0:
error_message = process.stderr.strip()
print(f"ERROR: Subprocess failed with code {process.returncode}:\n{error_message}", file=sys.stderr)
sys.exit(f"FAILED: {' '.join(command_list)}\n{error_message}")
# 6. 计算CPU时间
cpu_time_user = usage_end.ru_utime - usage_start.ru_utime
cpu_time_system = usage_end.ru_stime - usage_start.ru_stime
# 7. 写入报告文件
with open(report_file_path, "w") as f:
f.write(f"Command: {' '.join(command_list)}\n")
f.write(f"User CPU Time: {cpu_time_user:.6f} seconds\n")
f.write(f"System CPU Time: {cpu_time_system:.6f} seconds\n")
f.write(f"Peak RSS Memory: {max(memory_snapshots) if memory_snapshots else 0:.3f} GB\n")
f.write(f"Memory Snapshots (RSS in GB): {memory_snapshots}\n")
print(f"Monitoring complete. Report saved to {report_file_path}")
print(f"User CPU Time: {cpu_time_user:.6f} seconds")
print(f"System CPU Time: {cpu_time_system:.6f} seconds")
print(f"Peak RSS Memory: {max(memory_snapshots) if memory_snapshots else 0:.3f} GB")
print(f"Memory Snapshots (RSS in GB): {memory_snapshots}")
if __name__ == "__main__":
# 示例:运行一个模拟耗时且有一定CPU和内存使用的命令
# 这个Python脚本会进行一些计算并暂停,模拟真实工具的行为
# 注意:在某些系统上,Python解释器本身也会消耗一定的CPU和内存
command_to_run = [
sys.executable, "-c",
"import time, os; "
"data = [i*i for i in range(10**6)]; " # 模拟内存分配和一些计算
"time.sleep(2); " # 暂停2秒
"data2 = [x+1 for x in data]; " # 更多计算
"time.sleep(1); " # 暂停1秒
"print('Subprocess finished calculation and sleeping.');"
]
# 您也可以替换为您的生物信息学工具命令,例如:
# command_to_run = ["your_bioinformatics_tool", "--input", "file.fa", "--output", "result.txt"]
monitor_subprocess_performance(command_to_run, "tool_performance_report.txt", slice_in_seconds=1)
print("\n--- Testing a command with minimal CPU/memory (e.g., sleep) ---")
monitor_subprocess_performance(["sleep", "3"], "sleep_performance_report.txt", slice_in_seconds=1)以上就是Python在Unix环境下监控子进程的内存与CPU时间使用教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号