0

0

Python中Unix子进程的CPU时间与内存使用精确监控指南

聖光之護

聖光之護

发布时间:2025-12-05 13:08:27

|

750人浏览过

|

来源于php中文网

原创

Python中Unix子进程的CPU时间与内存使用精确监控指南

本文详细介绍了如何在python中利用subprocess、resource和psutil库精确监控unix子进程的cpu时间(用户态和系统态)及实时内存使用情况。重点阐述了resource.getrusage调用时机对cpu时间测量的关键影响,并提供了结合实时内存采样与正确cpu时间捕获的完整代码示例,旨在帮助开发者准确评估外部工具的性能表现。

引言:子进程性能监控的重要性

在许多场景下,例如运行生物信息学工具、批处理脚本或任何需要调用外部程序的Python应用中,准确监控这些子进程的性能至关重要。这不仅有助于评估不同工具或参数配置的效率,还能帮助识别性能瓶颈和优化资源使用。本教程将深入探讨如何使用Python标准库subprocess、resource以及第三方库psutil来精确测量子进程的CPU时间消耗和内存占用

核心工具介绍

在开始实践之前,我们首先了解一下将要使用的关键Python库:

  • subprocess: Python的标准库,用于创建和管理新的进程。它提供了比os.system更强大的功能,允许我们更好地控制子进程的输入、输出和错误流,并获取其返回码。
  • resource: 这是一个Unix特有的模块,提供了查询和修改系统资源限制以及资源使用情况的功能。其中,resource.getrusage()函数是测量进程及其子进程CPU时间的关键。
  • psutil: 一个跨平台的第三方库,用于获取系统运行的进程和系统利用率(CPU、内存、磁盘、网络等)的详细信息。它对于实时监控内存使用情况非常有用。

精确测量CPU时间

测量子进程的CPU时间是评估其计算效率的核心指标。resource.getrusage()函数能够返回一个包含多种资源使用情况的对象,其中ru_utime(用户态CPU时间)和ru_stime(系统态CPU时间)是我们需要关注的。

关键点:resource.getrusage(resource.RUSAGE_CHILDREN)的调用时机

立即学习Python免费学习笔记(深入)”;

resource.getrusage(resource.RUSAGE_CHILDREN)用于获取当前进程所有已终止子进程的资源使用情况。这意味着,要准确测量子进程的CPU时间,必须在子进程完成执行并终止后才能调用此函数来获取其累计的CPU时间。如果在子进程仍在运行时或尚未终止时调用,它将不会包含该子进程的完整CPU时间。

PathFinder
PathFinder

AI驱动的销售漏斗分析工具

下载

错误示例分析: 原始代码中,usage_end = resource.getrusage(resource.RUSAGE_CHILDREN)被放置在subprocess.Popen调用之后,但在r.poll()循环之前。这意味着当usage_end被调用时,子进程可能刚刚启动或尚未开始消耗显著的CPU时间,导致usage_end.ru_utime - usage_start.ru_utime计算结果为0。

正确做法: 将第二次resource.getrusage(resource.RUSAGE_CHILDREN)的调用移到确认子进程已终止的循环之后。

实时监控内存使用

虽然resource模块可以提供峰值内存使用(ru_maxrss),但psutil库提供了更灵活和实时的内存监控能力。我们可以通过周期性地采样系统或特定进程的内存信息,来了解子进程运行期间的内存占用趋势。

两种内存监控策略:

  1. 系统级内存监控(psutil.virtual_memory()): 这种方法获取的是整个系统的内存使用情况。当只有一个主要子进程在运行时,这种方法可以间接反映子进程对系统内存的影响。它提供了总内存、可用内存、已用内存和内存百分比等信息。

  2. 进程级内存监控(psutil.Process(pid).memory_info()): 如果需要更精确地了解特定子进程的内存使用,可以通过psutil.Process(pid)来获取该子进程的详细内存信息,例如常驻内存集大小(RSS)、虚拟内存大小(VMS)等。这通常是更推荐的做法,因为它排除了其他系统进程的影响。

本教程将主要演示系统级内存监控,并简要提及进程级监控的优势。

完整的性能监控实现

下面是一个结合了CPU时间测量和实时内存监控的Python脚本示例。

import sys
import os
import subprocess
import resource
import psutil
import time

def get_system_memory_info():
    """
    获取当前系统的内存使用信息(GB为单位)。
    """
    mem = psutil.virtual_memory()
    return {
        "total_memory": mem.total / (1024.0 ** 3),
        "available_memory": mem.available / (1024.0 ** 3),
        "used_memory": mem.used / (1024.0 ** 3),
        "memory_percentage": mem.percent
    }

def get_process_memory_info(pid):
    """
    获取指定PID进程的内存使用信息(MB为单位)。
    """
    try:
        process = psutil.Process(pid)
        mem_info = process.memory_info()
        return {
            "rss_mb": mem_info.rss / (1024.0 ** 2), # 常驻内存集大小
            "vms_mb": mem_info.vms / (1024.0 ** 2)  # 虚拟内存大小
        }
    except psutil.NoSuchProcess:
        return None # 进程可能已终止

def monitor_subprocess_performance(bioinformatics_tool, setups, resultdir, inputs, tbl_rep_file):
    """
    监控子进程的CPU时间与内存使用。
    """
    # 示例变量,实际应用中请替换为您的具体值
    # bioinformatics_tool = "your_bio_tool"
    # setups = "--some-setup-args"
    # resultdir = "/path/to/results"
    # inputs = "/path/to/input.fasta"
    # tbl_rep_file = "report_file.txt"

    print(f"开始监控工具: {bioinformatics_tool}")

    # 打开报告文件
    try:
        outrepfp = open(tbl_rep_file, "w")
    except IOError as e:
        sys.exit(f"错误: 无法打开报告文件 {tbl_rep_file}: {e}")

    SLICE_IN_SECONDS = 1 # 内存采样间隔

    # 1. 在子进程启动前记录资源使用
    usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)

    # 2. 构建并执行子进程命令
    cmd = '{0} {1} --tblout {2} {3}'.format(bioinformatics_tool, setups, resultdir, inputs)
    print(f"执行命令: {cmd}")

    # 使用subprocess.Popen执行命令
    # 注意: stdout=subprocess.DEVNULL 将标准输出重定向到空设备
    # stderr=subprocess.PIPE 将标准错误捕获到管道中,以便后续检查
    try:
        r = subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, encoding='utf-8')
    except FileNotFoundError:
        sys.exit(f"错误: 命令 '{bioinformatics_tool}' 未找到。请检查路径或环境变量。")
    except Exception as e:
        sys.exit(f"错误: 执行子进程失败: {e}")

    # 3. 实时监控内存使用,直到子进程结束
    system_memory_snapshots = []
    process_memory_snapshots = []

    # 获取子进程的PID,用于进程级内存监控
    child_pid = r.pid 
    print(f"子进程PID: {child_pid}")

    while r.poll() is None: # 检查子进程是否仍在运行
        system_memory_snapshots.append(get_system_memory_info())

        # 也可以同时监控子进程自身的内存
        proc_mem = get_process_memory_info(child_pid)
        if proc_mem:
            process_memory_snapshots.append(proc_mem)

        time.sleep(SLICE_IN_SECONDS)

    # 确保在子进程终止后,再进行一次资源使用记录
    # 4. 子进程终止后记录资源使用,以获取准确的CPU时间
    usage_end = resource.getrusage(resource.RUSAGE_CHILDREN) 

    # 5. 检查子进程返回码,处理潜在错误
    if r.returncode != 0:
        error_output = r.stderr.strip()
        sys.exit(f'FAILED: 命令 "{cmd}" 失败,返回码 {r.returncode}\n错误输出:\n{error_output}')

    # 6. 提取并计算性能指标
    # 提取系统已用内存的最大值(从采样数据中)
    max_system_used_memory_gb = 0
    if system_memory_snapshots:
        max_system_used_memory_gb = max(m['used_memory'] for m in system_memory_snapshots)

    # 提取子进程峰值RSS内存(如果进行了进程级监控)
    max_process_rss_mb = 0
    if process_memory_snapshots:
        max_process_rss_mb = max(m['rss_mb'] for m in process_memory_snapshots)

    # 计算CPU时间
    cpu_time_user = usage_end.ru_utime - usage_start.ru_utime
    cpu_time_system = usage_end.ru_stime - usage_start.ru_stime
    total_cpu_time = cpu_time_user + cpu_time_system

    # 7. 将测量结果写入报告文件
    report_line = (
        f"{bioinformatics_tool} "
        f"用户CPU时间: {cpu_time_user:.4f}s "
        f"系统CPU时间: {cpu_time_system:.4f}s "
        f"总CPU时间: {total_cpu_time:.4f}s "
        f"峰值系统已用内存: {max_system_used_memory_gb:.2f}GB "
        f"峰值进程RSS内存: {max_process_rss_mb:.2f}MB\n"
    )
    outrepfp.write(report_line)
    outrepfp.close()

    print(f"性能报告已写入: {tbl_rep_file}")
    print(report_line.strip())

# 示例调用 (请根据您的实际情况修改参数)
if __name__ == "__main__":
    # 假设的参数
    tool_name = "example_tool"
    tool_setups = "-i input.txt -o output.txt"
    results_dir = "./results"
    input_data = "data.csv"
    report_file_name = "performance_report.txt"

    # 创建一个模拟的外部工具脚本
    # 在实际环境中,这会是您的真实生物信息学工具
    with open("example_tool", "w") as f:
        f.write("#!/bin/bash\n")
        f.write("echo 'Running example tool...' >&2\n")
        f.write("sleep 3 # 模拟工作3秒\n")
        f.write("echo 'Example tool finished.' >&2\n")
        f.write("exit 0\n")
    os.chmod("example_tool", 0o755) # 赋予执行权限

    # 创建模拟的results目录
    os.makedirs(results_dir, exist_ok=True)

    monitor_subprocess_performance(
        tool_name,
        tool_setups,
        results_dir,
        input_data,
        report_file_name
    )

    # 清理模拟文件
    os.remove("example_tool")
    os.rmdir(results_dir)

代码解析与注意事项

  1. get_system_memory_info(): 提供了系统整体的内存快照。这有助于了解子进程运行期间整个系统的内存压力。
  2. get_process_memory_info(pid): 这是一个增强功能,可以直接获取由pid标识的子进程的内存使用情况。rss_mb(常驻内存集)通常是衡量实际物理内存占用更重要的指标。
  3. usage_start 和 usage_end 的位置:
    • usage_start 必须在subprocess.Popen之前调用,以记录初始状态。
    • usage_end 必须在while r.poll() is None:循环之后调用,确保子进程已终止,resource模块才能准确汇总其CPU时间。
  4. while r.poll() is None: 循环: 这是等待子进程完成并进行实时监控的关键。r.poll()返回None表示子进程仍在运行,返回非None(通常是其返回码)表示子进程已终止。
  5. 内存采样间隔 SLICE_IN_SECONDS: 决定了内存监控的粒度。较小的值会增加开销但提供更精细的数据;较大的值开销小但可能错过瞬时峰值。
  6. 错误处理:
    • subprocess.Popen可能因命令不存在 (FileNotFoundError) 或其他原因失败。
    • 子进程本身可能以非零返回码结束,表示执行失败。r.returncode用于检查这一点,并通过r.stderr捕获错误输出。
  7. stdout=subprocess.DEVNULL 和 stderr=subprocess.PIPE:
    • DEVNULL将子进程的标准输出重定向到空设备,避免在控制台打印大量信息。
    • PIPE将标准错误捕获到Python脚本中,方便在子进程失败时进行检查和记录。
  8. CPU时间与墙钟时间(Wall-Clock Time):
    • resource模块测量的是CPU时间,即CPU实际花费在进程上的时间,不包括等待I/O或空闲的时间。
    • 如果需要测量墙钟时间(即从开始到结束的实际流逝时间),可以使用time.time()或time.monotonic()在进程启动前后进行记录。

总结

通过结合subprocess、resource和psutil库,我们可以构建一个强大而灵活的性能监控系统,用于评估Python中Unix子进程的CPU时间和内存使用。理解resource.getrusage的正确调用时机是获取准确CPU时间的关键,而psutil则提供了实时、细粒度的内存监控能力。遵循本教程中的方法和最佳实践,您将能够更有效地分析和优化您的外部工具和脚本的性能。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

181

2023.12.20

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

107

2023.09.25

unix和linux的区别
unix和linux的区别

unix和linux的区别包括发展历史、开源性、发行版本、内核、文件系统、应用程序兼容性和用户界面等。本专题为大家提供unix和linux相关的文章、下载、课程内容,供大家免费下载体验。

392

2023.09.22

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

136

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

47

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

90

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

226

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号