resource en Python: límites de CPU y memoria

Publicado el: 26/08/2026
Tempo de leitura: 5 minutos
A CPU and RAM sticks displayed on a white surface, showcasing computer hardware components.

El módulo resource mide y limita recursos usados por procesos Unix. Puede informar tiempo de CPU, page faults, context switches y pico de memoria, además de imponer cotas para file descriptors, tamaño de archivos, address space, creación de procesos y otros recursos soportados.

Estos controles son útiles al ejecutar plugins, compiladores, conversores, tareas de usuarios o subprocesses que no deben consumir CPU, memoria o disco sin límite. No sustituyen containers, cgroups, sandboxes o usuarios sin privilegios, pero añaden una capa defensiva.

Disponibilidad

resource existe en Unix y no en WASI. Las constantes cambian por plataforma, así que comprueba con hasattr().

import resource

if hasattr(resource, "RLIMIT_AS"):
    print(resource.getrlimit(resource.RLIMIT_AS))

No asumas que Linux, macOS y BSD ofrecen o aplican los mismos límites.

Soft y hard limit

Cada recurso tiene un par (soft, hard). El soft se aplica actualmente. Un proceso puede bajarlo y normalmente volver a subirlo hasta el hard. Elevar el hard requiere privilegios.

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print("Soft:", soft, "Hard:", hard)

RLIM_INFINITY representa ilimitado cuando el sistema lo permite.

No reduzcas el hard sin necesidad

Después de bajar el hard, un proceso sin privilegios no puede restaurarlo. Para limitaciones temporales, conserva hard y cambia solo soft.

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
resource.setrlimit(resource.RLIMIT_NOFILE, (min(256, hard), hard))

Incluso cambiar el soft del proceso principal puede romper bibliotecas cargadas después. Prefiere un hijo dedicado.

Limitar file descriptors

RLIMIT_NOFILE controla cuántos descriptors pueden estar abiertos.

def limitar_fds(maximo=128):
    soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
    valor = min(maximo, hard)
    resource.setrlimit(resource.RLIMIT_NOFILE, (valor, hard))

Al agotarse, operaciones pueden lanzar EMFILE. Cierra archivos, sockets y pipes correctamente.

Limitar CPU

RLIMIT_CPU cuenta segundos de CPU, no tiempo de reloj.

resource.setrlimit(resource.RLIMIT_CPU, (2, 3))

Superar soft envía SIGXCPU. Llegar a hard puede terminar el proceso.

Una tarea dormida o esperando red puede durar mucho más sin consumir CPU. Usa también timeout externo.

Manejar SIGXCPU

import signal


def cpu_excedida(signum, frame):
    guardar_estado_minimo()
    raise SystemExit(124)

if hasattr(signal, "SIGXCPU"):
    signal.signal(signal.SIGXCPU, cpu_excedida)

Mantén el handler corto. signal en Python explica los riesgos de locks y logging.

Limitar tamaño de archivos

RLIMIT_FSIZE limita el tamaño máximo de un archivo creado.

limite = 10 * 1024 * 1024
resource.setrlimit(resource.RLIMIT_FSIZE, (limite, limite))

No limita el número de archivos ni todo el filesystem. Usa cuota o directorio aislado para protección adicional.

Limitar address space

RLIMIT_AS limita memoria virtual.

if hasattr(resource, "RLIMIT_AS"):
    limite = 512 * 1024 * 1024
    resource.setrlimit(resource.RLIMIT_AS, (limite, limite))

Bibliotecas científicas, mmap, shared objects y allocators reservan espacio virtual que no equivale al RSS. Un valor bajo puede impedir imports o generar MemoryError.

RLIMIT_DATA y RLIMIT_RSS

RLIMIT_DATA tradicionalmente limita heap, pero allocations modernas pueden evitarlo. RLIMIT_RSS puede ser advisory.

Para memoria en producción, cgroups o limits de container suelen ser más predecibles.

Stack

RLIMIT_STACK limita la stack del thread principal. Bajarlo demasiado puede provocar crash en recursión, extensiones C o inicialización.

Número de procesos

RLIMIT_NPROC limita creación de procesos según la plataforma.

if hasattr(resource, "RLIMIT_NPROC"):
    soft, hard = resource.getrlimit(resource.RLIMIT_NPROC)
    resource.setrlimit(resource.RLIMIT_NPROC, (min(32, hard), hard))

Threads pueden contar y servicios con el mismo usuario pueden competir.

Aplicar límites en un wrapper

preexec_fn puede ser peligroso en un padre multithread. Un wrapper simple es más seguro.

# wrapper_limitado.py
import os
import resource
import sys

resource.setrlimit(resource.RLIMIT_CPU, (2, 3))
resource.setrlimit(resource.RLIMIT_FSIZE, (10_000_000, 10_000_000))
os.execvp(sys.argv[1], sys.argv[1:])

El padre inicia el wrapper con lista de argumentos, sin shell.

prlimit()

En Linux, prlimit() consulta o modifica límites de otro proceso con permisos.

if hasattr(resource, "prlimit"):
    anterior = resource.prlimit(pid, resource.RLIMIT_NOFILE, (128, 128))
    print(anterior)

Puede lanzar ProcessLookupError o PermissionError. Verifica identidad porque los PIDs se reutilizan.

Auditoría

setrlimit() y prlimit() generan eventos de auditoría.

getrusage()

getrusage() informa sobre el proceso actual, hijos recolectados o thread actual.

uso = resource.getrusage(resource.RUSAGE_SELF)
print("CPU usuario:", uso.ru_utime)
print("CPU sistema:", uso.ru_stime)
print("Pico RSS:", uso.ru_maxrss)

RUSAGE_SELF incluye todas las threads. RUSAGE_CHILDREN incluye hijos terminados y esperados.

Unidades de ru_maxrss

La unidad depende de la plataforma. Linux normalmente devuelve KiB y macOS bytes. Normaliza antes de mostrar MB.

import platform

valor = uso.ru_maxrss
rss_bytes = valor if platform.system() == "Darwin" else valor * 1024

Valida esta regla en otros Unix.

Pico no es memoria actual

ru_maxrss representa el máximo observado y no disminuye al liberar memoria.

Para una serie temporal, usa procfs, psutil o métricas del container.

Tiempo de CPU

ru_utime mide user mode y ru_stime kernel mode.

antes = resource.getrusage(resource.RUSAGE_SELF)
ejecutar_trabajo()
despues = resource.getrusage(resource.RUSAGE_SELF)

cpu = (despues.ru_utime - antes.ru_utime) + (despues.ru_stime - antes.ru_stime)

Para microbenchmarks, usa timeit.

Page faults

ru_minflt cuenta faults sin I/O y ru_majflt los que requieren almacenamiento. Dependen de cache, kernel y entorno.

Context switches

ru_nvcsw cuenta cambios voluntarios y ru_nivcsw involuntarios. Muchos involuntarios pueden indicar competencia por CPU.

Operaciones de bloque

ru_inblock y ru_oublock representan operaciones, no bytes.

Hijos recolectados

Para aparecer en RUSAGE_CHILDREN, el hijo debe terminar y ser recolectado con wait() o waitpid().

Tamaño de página

print(resource.getpagesize())

No describe necesariamente huge pages ni todos los detalles de hardware.

Los límites no son sandbox

Un proceso limitado puede acceder a archivos permitidos, red, entorno y credenciales. Combina rlimits con usuario sin privilegios, directorios aislados, allowlist y containers.

Aplicar temprano

Define límites antes de cargar contenido no confiable. Reducir una cota no deshace recursos ya consumidos.

Diagnóstico

Registra los límites efectivos. Al terminar por señal, informa que CPU, archivos o memoria pueden ser responsables sin afirmar certeza absoluta.

Pruebas

Prueba constantes ausentes, soft mayor que hard, intento de subir hard, CPU-bound, sleep, archivos, descriptors, imports bajo RLIMIT_AS, hijos, threads, Linux/macOS y container.

Errores comunes

Los fallos frecuentes son limitar el proceso principal, confundir CPU y wall time, tratar ru_maxrss como memoria actual, ignorar unidades, bajar hard de forma irreversible, asumir RLIMIT_RSS rígido y llamar sandbox a los rlimits.

Conclusión

resource mide consumo e impone cotas Unix básicas. Funciona mejor en procesos hijos dedicados con limits definidos antes del trabajo y monitoreo externo.

Comprueba constantes, normaliza métricas y combina rlimits con aislamiento real. Consulta la documentación oficial de resource y getrlimit(2).

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Rack de servidores que representa el balanceo de conexiones con SO_REUSEPORT_LB en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: reparte conexiones entre workers

    Aprende SO_REUSEPORT_LB en Python para distribuir conexiones entre workers con pruebas, portabilidad y cierre ordenado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Código Python para representar fracciones exactas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: convierte números en fracciones

    Aprende fractions.from_number en Python para convertir números en fracciones exactas, controlar precisión, validar entradas y evitar redondeos inesperados.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026
    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026