news 2026/9/8 18:31:27

CPython `resource` 模块深度指南:进程资源限制(RLIMIT_*)与用量统计(getrusage)实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CPython `resource` 模块深度指南:进程资源限制(RLIMIT_*)与用量统计(getrusage)实践

CPythonresource模块深度指南:进程资源限制(RLIMIT_*)与用量统计(getrusage)实践

【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython

resource是 CPython 中用于测量与控制当前进程系统资源消耗的标准库模块,直接封装了 Unix 系统调用getrlimit(2)setrlimit(2)prlimit(2)getrusage(2)getpagesize(3)。本文以 CPython 官方文档 Doc/library/resource.rst 为骨架,结合其 C 实现 Modules/resource.c 与测试用例 Lib/test/test_resource.py,完整讲解软/硬限制机制、全部RLIMIT_*常量、getrusage返回的 16 个字段语义,并给出可运行、可防护的实战代码,帮助你读懂并驾驭进程的 CPU、内存、文件描述符等资源边界。


模块概览与适用平台

resource模块提供两类能力:

  • 资源限制(Resource Limits):通过getrlimit()/setrlimit()/prlimit()查看并调整进程在 CPU 时间、堆内存、栈、文件大小、打开文件数等方面的上下限;
  • 资源用量(Resource Usage):通过getrusage()获取进程自身或子进程已消耗的 CPU 用户态/内核态时间、内存、缺页、上下文切换等统计信息。

可用性(Availability)

  • 平台:Unix(Linux、macOS、BSD、Solaris、AIX 等),不支持 WASI
  • 由于 Windows 没有这些系统调用语义,resource在 Windows 上不可用;
  • 因此文档与源码中大量使用@unittest.skipUnless(hasattr(resource, ...))进行平台适配(见 Lib/test/test_resource.py)。

异常与兼容别名

底层系统调用失败时统一抛出OSErrorresource.errorOSError已弃用别名——自 3.3 起(遵循 PEP 3151),两者完全等价,新代码应直接使用OSError。在 Modules/resource.c 中可以看到别名通过PyModule_AddObjectRef(module, "error", PyExc_OSError)直接绑定到内置异常类型实现。


资源限制机制:软限制与硬限制

每个可限制资源都由一对限制值控制:

概念含义能否被进程自身修改
软限制(soft limit /rlim_cur当前生效的限制值可随时间升高或降低,但永远不能超过硬限制
硬限制(hard limit /rlim_max软限制的绝对上限只能降低到不低于软限制的值,不能调高;只有有效 UID 为超级用户(root)的进程才能提升硬限制

这一规则对应系统调用getrlimit(2)/setrlimit(2)的 man page 语义;模块不掩盖平台差异,某平台不支持的资源符号在该平台上不会出现在模块中

哨兵常量

  • RLIM_INFINITY:表示"无限制"的特殊值。文档指出自3.15起它恒为正数(此前可能是 -1、-3 等负数);测试 test_fsize_ismax 显式断言resource.RLIM_INFINITY > 0
  • RLIM_SAVED_CUR/RLIM_SAVED_MAX3.15 新增):当真正的软/硬限制值无法用 C 的rlim_t类型表示时,用于代表"保存的"软/硬限制;取值可能等于RLIM_INFINITY。实现中两者按平台宏条件加入模块,见 Modules/resource.c。

关于"传入负数"的兼容行为:从 Modules/resource.c 的py2rlim()可以看到——负值若恰好等于RLIM_INFINITY的旧编码,会发出DeprecationWarning: "Use RLIM_INFINITY instead of negative limit value.";其他负数一律抛ValueError。测试 test_fsize_negative 覆盖了这一规则。相关变更记录见 Misc/NEWS.d/3.15.0a1.rst。


三大核心函数

getrlimit(resource)

查询某个资源当前的软、硬限制:

import resource soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) print(f"soft={soft}, hard={hard}")
  • 返回形如(soft, hard)的二元组;
  • 传入非法资源编号ValueError(源码在 Modules/resource.c 中对resource < 0 || resource >= RLIM_NLIMITS进行拦截);
  • 系统调用意外失败抛OSError
  • 返回的两个值均为 Python 无符号整数(经rlim2py()PyLong_FromUnsignedNativeBytes转换,Modules/resource.c),因此即使上限极大(如RLIM_INFINITY)也不会出现负数或溢出。

setrlimit(resource, limits)

设置资源的新消费上限:

resource.setrlimit(resource.RLIMIT_NOFILE, (4096, 8192))
  • limits必须是两个整数组成的元组(soft, hard),可用RLIM_INFINITY表示不限量;
  • 参数校验(见 py2rlimit):不是二元元组会抛ValueError(错误信息为"expected a tuple of 2 integers"),元素类型错误抛TypeError,超出 Crlim_t范围抛OverflowError——测试 test_args 对各类非法输入做了穷举断言;
  • 违反限制规则时抛ValueError,包括:
    • 新软限制超过硬限制(errnoEINVAL"current limit exceeds maximum limit");
    • 尝试提升硬限制但权限不足(errnoEPERM"not allowed to raise maximum limit");
    • 请求RLIM_INFINITY但该资源的硬/系统上限并非无限;
    • 超级用户可以请求任意合法值,但若超出系统施加的上限仍会抛ValueError
  • 底层调用失败同样抛OSError。错误到异常的映射见 Modules/resource.c;
  • 审计事件:每次调用触发resource.setrlimit(resource, limits)(参数依次为资源编号、限制对象),供审计钩子拦截;
  • VxWorks 特例:仅支持设置RLIMIT_NOFILE

一个安全的实践是"先读后写、用完还原",CPython 测试框架自身正是这样处理核心文件限制的(见 Lib/test/support/init.py):

soft, hard = resource.getrlimit(resource.RLIMIT_CORE) old_soft, old_hard = soft, hard try: # 临时下调 core 文件上限,避免测试误产生巨大 core dump resource.setrlimit(resource.RLIMIT_CORE, (0, hard)) ... finally: resource.setrlimit(resource.RLIMIT_CORE, (old_soft, old_hard))

prlimit(pid, resource[, limits])(Linux)

setrlimitgetrlimit合并为一次调用,可作用于任意进程

  • pid == 0表示当前进程;
  • 省略limits:仅查询进程pid的该资源限制;
  • 提供limits:先设置新限制,返回旧限制(soft, hard)
  • 异常:pid不存在抛ProcessLookupError;无CAP_SYS_RESOURCE权限访问目标进程抛PermissionError(其余错误为OSError,见 Modules/resource.c);
  • 审计事件resource.prlimit(pid, resource, limits)
  • 可用性:Linux ≥ 2.6.36 且 glibc ≥ 2.13(由HAVE_PRLIMIT宏控制编译,Modules/resource.c);
  • 3.4 加入

例如用prlimit另一个进程的地址空间上限收紧为 2 GiB:

import os, resource pid = int(os.environ.get("TARGET_PID", "0")) old = resource.prlimit(pid, resource.RLIMIT_AS, (2 * 1024**3, 2 * 1024**3)) print("old limits were:", old)

测试 test_prlimit 同时验证了查询模式与设置模式,并断言对不存在的 pid 抛ProcessLookupError


资源限制常量:RLIMIT_*全表

以下符号的值与 C 程序使用的常量完全一致,可在setrlimit/getrlimit/prlimit中直接使用。具体哪些可用取决于操作系统与内核版本——本模块不掩盖平台差异,未定义的符号在该平台不可用(这与文档一致)。下方标注了官方文档记载的可用性条件与加入版本。

常量含义可用性 / 版本
RLIMIT_CORE进程可生成的 core 文件最大字节数;超出时可能生成不完整的部分 core通用
RLIMIT_CPU进程可使用的 CPU 时间上限(秒);超限后内核向进程发送SIGXCPU信号,可用signal模块捕获并处理(如落盘缓冲)通用
RLIMIT_FSIZE进程可创建文件的最大字节数通用
RLIMIT_DATA进程堆(heap)的最大字节数通用
RLIMIT_STACK进程调用栈最大字节数;多线程进程中只影响主线程的栈通用
RLIMIT_RSS进程可获得的常驻内存集(resident set size)上限通用
RLIMIT_NPROC当前进程可创建的子进程数量上限通用
RLIMIT_NOFILE当前进程可打开的文件描述符数量上限通用
RLIMIT_OFILERLIMIT_NOFILE的 BSD 别名BSD
RLIMIT_MEMLOCK可锁定在物理内存中的地址空间大小上限通用
RLIMIT_VMEM进程可占用的映射内存最大区域;通常是RLIMIT_AS的别名Solaris / FreeBSD / NetBSD
RLIMIT_AS进程可占用的地址空间最大字节数通用
RLIMIT_MSGQUEUEPOSIX 消息队列可分配的总字节数Linux ≥ 2.6.8,3.4 加入
RLIMIT_NICE进程 nice 值的天花板(按20 - rlim_cur计算)Linux ≥ 2.6.12,3.4 加入
RLIMIT_RTPRIO实时优先级天花板Linux ≥ 2.6.12,3.4 加入
RLIMIT_RTTIME实时调度下、不做阻塞系统调用可花费的 CPU 时间上限(微秒)Linux ≥ 2.6.25,3.4 加入
RLIMIT_SIGPENDING进程可排队的信号数量上限Linux ≥ 2.6.8,3.4 加入
RLIMIT_SBSIZE该用户可占用的套接字缓冲区总字节数(网络内存/mbufs)FreeBSD / NetBSD,3.4 加入
RLIMIT_SWAP该用户 ID 所有进程可保留/使用的交换空间字节数(仅当vm.overcommitsysctl 第 1 位开启时强制)FreeBSD ≥ 8,3.4 加入
RLIMIT_NPTS该用户 ID 可创建的伪终端数量上限FreeBSD ≥ 8,3.4 加入
RLIMIT_KQUEUES该用户 ID 可创建的 kqueue 数量上限FreeBSD ≥ 11,3.10 加入
RLIMIT_NTHR该用户 ID 的线程数上限(不计主线程与内核线程)NetBSD ≥ 7.0,3.15 加入
RLIMIT_PIPEBUF该用户 ID 可消耗的双向 pipe/fifo 内核缓冲区总量上限FreeBSD ≥ 14.2,3.15 加入
RLIMIT_THREADS每个进程可创建的线程数上限AIX,3.15 加入
RLIMIT_UMTXP该用户 ID 分配的进程共享 POSIX 线程库对象数量上限FreeBSD ≥ 11,3.15 加入

这些常量在 Modules/resource.c 中逐一以#ifdef条件编译加入(ADD_INT宏),与 C 头文件中的同名宏一一对应;测试 test_linux_constants 与 test_freebsd_contants 分别校验了 Linux 与 FreeBSD 专属常量均为int

实战选型提醒:若需保证跨平台脚本不报AttributeError,请先用hasattr(resource, "RLIMIT_XXX")探测,这与模块"不掩盖平台差异"的设计保持一致。


用量统计:getrusagegetpagesizeRUSAGE_*

getrusage(who)

返回当前进程或其子进程的资源消耗描述对象,whoRUSAGE_*常量指定。官方文档给出了一个直观示例(本处稍作整理):

from resource import * import time # 非 CPU 密集型任务 time.sleep(3) print(getrusage(RUSAGE_SELF)) # CPU 密集型任务 for i in range(10 ** 8): _ = 1 + 1 print(getrusage(RUSAGE_SELF))

两次输出对比中,第二次的ru_utime(用户态时间)会明显增大,可用来验证"测的是 CPU 忙等时间还是挂起时间"。

返回值类型:该对象是 CPython 定义的结构序列(struct sequence)类型struct_rusage,字段顺序与 16 元组完全一致,既能按属性访问(ru_utime),也能按下标/解包按元组访问。类型定义见 Modules/resource.c,字段构建在getrusage实现中逐个填充(Modules/resource.c)。

官方文档的字段总表(含元组下标):

下标字段含义
0ru_utime用户态运行时间(浮点秒)
1ru_stime系统态运行时间(浮点秒)
2ru_maxrss最大常驻内存集大小
3ru_ixrss共享内存大小
4ru_idrss非共享内存大小
5ru_isrss非共享栈大小
6ru_minflt无需 I/O 的缺页次数
7ru_majflt需要 I/O 的缺页次数
8ru_nswap换出次数
9ru_inblock块输入操作次数
10ru_oublock块输出操作次数
11ru_msgsnd发送的消息数
12ru_msgrcv接收的消息数
13ru_nsignals收到的信号数
14ru_nvcsw主动上下文切换次数
15ru_nivcsw被动上下文切换次数
  • ru_utimeru_stime为浮点数(源码中由doubletime()tv_sec + tv_usec * 1e-6换算成秒,Modules/resource.c),其余字段为整数;
  • 部分数值依赖时钟 tick 粒度(如ru_maxrss在部分系统以 KB 为单位);
  • 传非法whoValueError(源码把 errnoEINVAL映射为ValueError,Modules/resource.c),其余异常抛OSError

RUSAGE_*who取值

常量含义版本
RUSAGE_SELF调用进程自身消耗的资源(为进程内所有线程之和)通用
RUSAGE_CHILDREN已终止并被wait回收的子进程消耗的资源通用
RUSAGE_BOTH当前进程与子进程之和;部分系统不可用
RUSAGE_THREAD仅当前线程消耗的资源;部分系统不可用3.2 加入

在自由线程(free-threaded)构建下,RUSAGE_THREAD对多线程程序尤其有用——测试 Lib/test/test_free_threading/test_resource.py 分别对比了RUSAGE_SELFRUSAGE_THREAD的结果。

getpagesize()

返回系统页大小(字节数),注意未必等于硬件页大小

>>> import resource >>> resource.getpagesize() 4096

实现上优先调用getpagesize(),否则回退到sysconf(_SC_PAGE_SIZE),见 Modules/resource.c;测试 test_pagesize 断言其为非负整数。


底层实现细节:从 Python 参数到 Crlim_t

理解数值转换有助于避免边界踩坑:

  1. getrlimit的资源校验:先拦截越界资源编号(抛ValueError),再调用系统调用,见 Modules/resource.c;
  2. py2rlim()无符号转换(Modules/resource.c):支持任意实现__index__的对象;负数整体抛ValueError,与RLIM_INFINITY等价的旧式负哨兵值则触发DeprecationWarning;Python 整数超出 Crlim_t宽度时抛OverflowError
  3. rlim2py()反向转换(Modules/resource.c):按无符号原生字节序构造 Python 整数,保证RLIM_INFINITYRLIM_SAVED_CUR/MAX这些大哨兵值无损往返;
  4. 模块级并发安全struct_rusage类型存放于 per-module state(resourcemodulestate),且模块槽位声明了Py_MOD_PER_INTERPRETER_GIL_SUPPORTEDPy_MOD_GIL_NOT_USED(Modules/resource.c),表明该模块在多解释器与自由线程(free-threaded)构建下均可安全使用。

在 CPython 生态中的真实应用场景

1. 测试运行器提升文件描述符上限:CPython 的测试框架在运行前会读取RLIMIT_NOFILE,必要时临时把软限制提高到接近硬限制,以保证大量并发套接字/文件句柄的测试不被系统默认限制卡死,见 Lib/test/libregrtest/utils.py。

2. 环境信息采集resource.getrlimit(...)resource.getrusage(...)被用于测试报告辅助脚本,把软/硬限制与资源用量写入诊断信息,见 Lib/test/pythoninfo.py。

3. 限制真正生效的验证:测试 test_fsize_enforced 演示了端到端行为——将RLIMIT_FSIZE软限制设为 1024 字节后,写入第 1025 字节即触发OSErrorSIGXFSZ语义),并在finally中恢复原限制。该模式正是"给不可信任务上保险丝"的范本:

import resource, signal, time def run_with_cpu_guard(seconds): soft, hard = resource.getrlimit(resource.RLIMIT_CPU) def handler(signum, frame): raise TimeoutError("CPU 配额耗尽") old = signal.signal(signal.SIGXCPU, handler) try: resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard)) ... # 执行你的计算任务 finally: resource.setrlimit(resource.RLIMIT_CPU, (soft, hard)) signal.signal(signal.SIGXCPU, old)

说明:RLIMIT_CPU超限后内核先发SIGXCPU(默认动作是终止进程),Python 中可通过signal模块捕获该信号执行清理或转储,这正是文档 Doc/library/resource.rst 在RLIMIT_CPU条目中特别提醒的用法。

4. 运行期可观测性:在长期服务中周期性采样getrusage(RUSAGE_SELF).ru_maxrss与上下文切换计数,可廉价地获得内存与调度健康度指标,无需引入外部监控依赖。


相关参考路径

  • 权威接口文档:Doc/library/resource.rst
  • C 实现(常量注入、参数校验、系统调用封装):Modules/resource.c
  • 完整测试(边界值、跨平台、refcount、prlimit):Lib/test/test_resource.py
  • 自由线程下的RUSAGE_THREAD测试:Lib/test/test_free_threading/test_resource.py
  • 3.15 新增常量与RLIM_INFINITY语义变更记录:Misc/NEWS.d/3.15.0a1.rst
  • 当前仓库版本(本仓库主分支对应 3.16 开发版):Include/patchlevel.h

一句话总结:凡是涉及"限制自身或子进程的 CPU/内存/文件资源"或"测量自身消耗了多少 CPU 时间、内存、IO 与调度代价"的需求,在 Unix 平台优先想到resource——它薄薄一层直接映射系统调用,是最轻量、最可靠的基础设施之一。

【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 18:29:09

手把手教你学Simulink--基于虚拟阻抗的并网逆变器输出特性控制

### 手把手教你学Simulink--基于虚拟阻抗的并网逆变器输出特性控制 #### 摘要 本研究旨在探讨如何借助Simulink实现基于虚拟阻抗的并网逆变器输出特性控制。通过理论分析,深入剖析虚拟阻抗对并网逆变器输出特性的影响机制;借助Simulink搭建详细模型,包括主电路、虚拟阻抗模…

作者头像 李华
网站建设 2026/9/8 18:27:41

眼睛开闭检测数据集实战:VOC转YOLO格式与YOLOv8训练全流程

简介&#xff1a;面向眼睛睁开闭合检测任务的数据集包&#xff0c;为计算机视觉目标检测训练提供标准化数据基础&#xff0c;适用于疲劳驾驶预警、注意力分析等场景。数据集包含12884张人脸/眼部图片&#xff0c;对应VOC格式XML标注与YOLO格式TXT标签各12884份&#xff0c;标注…

作者头像 李华
网站建设 2026/9/8 18:25:46

MCP如何让Tool与LLM真正解耦?从零搭建MCP Server的避坑实录

你如果最近在折腾 Agent&#xff0c;会发现 MCP、Tool、LLM 解耦这些词频繁出现在同一条时间线里。我踩了一周坑后确认&#xff1a;MCP 真正擅长的是把工具调用做成跨进程、跨语言的标准通信&#xff0c;而不是给 LLM 塞一份更大的 JSON。很多人第一次看到 MCP 的反应是&#x…

作者头像 李华
网站建设 2026/9/8 18:23:54

opencode开源AI编程代理:从配置到实战的全解析

opencode这个词&#xff0c;最近在AI编程圈里热度蹿得很快。简单说&#xff0c;它是一个跑在终端里的AI编程代理工具&#xff0c;能理解你的自然语言指令&#xff0c;然后自动完成读代码、改文件、执行命令、跑测试、修Bug这一整套流程。你问它“这个项目的登录流程哪一步会报错…

作者头像 李华
网站建设 2026/9/8 18:23:14

基于SpringBoot的实训项目管理平台(源码+文档+部署+讲解)

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华