与用量统计(getrusage)实践)
CPythonresource模块深度指南进程资源限制RLIMIT_*与用量统计getrusage实践【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpythonresource是 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平台UnixLinux、macOS、BSD、Solaris、AIX 等不支持 WASI由于 Windows 没有这些系统调用语义resource在 Windows 上不可用因此文档与源码中大量使用unittest.skipUnless(hasattr(resource, ...))进行平台适配见 Lib/test/test_resource.py。异常与兼容别名底层系统调用失败时统一抛出OSErrorresource.error是OSError的已弃用别名——自 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(fsoft{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.pysoft, 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把setrlimit与getrlimit合并为一次调用可作用于任意进程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.c3.4 加入。例如用prlimit把另一个进程的地址空间上限收紧为 2 GiBimport 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 别名BSDRLIMIT_MEMLOCK可锁定在物理内存中的地址空间大小上限通用RLIMIT_VMEM进程可占用的映射内存最大区域通常是RLIMIT_AS的别名Solaris / FreeBSD / NetBSDRLIMIT_AS进程可占用的地址空间最大字节数通用RLIMIT_MSGQUEUEPOSIX 消息队列可分配的总字节数Linux ≥ 2.6.83.4 加入RLIMIT_NICE进程 nice 值的天花板按20 - rlim_cur计算Linux ≥ 2.6.123.4 加入RLIMIT_RTPRIO实时优先级天花板Linux ≥ 2.6.123.4 加入RLIMIT_RTTIME实时调度下、不做阻塞系统调用可花费的 CPU 时间上限微秒Linux ≥ 2.6.253.4 加入RLIMIT_SIGPENDING进程可排队的信号数量上限Linux ≥ 2.6.83.4 加入RLIMIT_SBSIZE该用户可占用的套接字缓冲区总字节数网络内存/mbufsFreeBSD / NetBSD3.4 加入RLIMIT_SWAP该用户 ID 所有进程可保留/使用的交换空间字节数仅当vm.overcommitsysctl 第 1 位开启时强制FreeBSD ≥ 83.4 加入RLIMIT_NPTS该用户 ID 可创建的伪终端数量上限FreeBSD ≥ 83.4 加入RLIMIT_KQUEUES该用户 ID 可创建的 kqueue 数量上限FreeBSD ≥ 113.10 加入RLIMIT_NTHR该用户 ID 的线程数上限不计主线程与内核线程NetBSD ≥ 7.03.15 加入RLIMIT_PIPEBUF该用户 ID 可消耗的双向 pipe/fifo 内核缓冲区总量上限FreeBSD ≥ 14.23.15 加入RLIMIT_THREADS每个进程可创建的线程数上限AIX3.15 加入RLIMIT_UMTXP该用户 ID 分配的进程共享 POSIX 线程库对象数量上限FreeBSD ≥ 113.15 加入这些常量在 Modules/resource.c 中逐一以#ifdef条件编译加入ADD_INT宏与 C 头文件中的同名宏一一对应测试 test_linux_constants 与 test_freebsd_contants 分别校验了 Linux 与 FreeBSD 专属常量均为int。实战选型提醒若需保证跨平台脚本不报AttributeError请先用hasattr(resource, RLIMIT_XXX)探测这与模块不掩盖平台差异的设计保持一致。用量统计getrusage、getpagesize与RUSAGE_*getrusage(who)返回当前进程或其子进程的资源消耗描述对象who由RUSAGE_*常量指定。官方文档给出了一个直观示例本处稍作整理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_utime、ru_stime为浮点数源码中由doubletime()把tv_sec tv_usec * 1e-6换算成秒Modules/resource.c其余字段为整数部分数值依赖时钟 tick 粒度如ru_maxrss在部分系统以 KB 为单位传非法who抛ValueError源码把 errnoEINVAL映射为ValueErrorModules/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_SELF与RUSAGE_THREAD的结果。getpagesize()返回系统页大小字节数注意未必等于硬件页大小 import resource resource.getpagesize() 4096实现上优先调用getpagesize()否则回退到sysconf(_SC_PAGE_SIZE)见 Modules/resource.c测试 test_pagesize 断言其为非负整数。底层实现细节从 Python 参数到 Crlim_t理解数值转换有助于避免边界踩坑getrlimit的资源校验先拦截越界资源编号抛ValueError再调用系统调用见 Modules/resource.cpy2rlim()无符号转换Modules/resource.c支持任意实现__index__的对象负数整体抛ValueError与RLIM_INFINITY等价的旧式负哨兵值则触发DeprecationWarningPython 整数超出 Crlim_t宽度时抛OverflowErrorrlim2py()反向转换Modules/resource.c按无符号原生字节序构造 Python 整数保证RLIM_INFINITY、RLIM_SAVED_CUR/MAX这些大哨兵值无损往返模块级并发安全struct_rusage类型存放于 per-module stateresourcemodulestate且模块槽位声明了Py_MOD_PER_INTERPRETER_GIL_SUPPORTED与Py_MOD_GIL_NOT_USEDModules/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.rstC 实现常量注入、参数校验、系统调用封装Modules/resource.c完整测试边界值、跨平台、refcount、prlimitLib/test/test_resource.py自由线程下的RUSAGE_THREAD测试Lib/test/test_free_threading/test_resource.py3.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),仅供参考