El parámetro track de multiprocessing.shared_memory.SharedMemory controla si un segmento de memoria compartida se registra en el resource tracker de multiprocessing. Esta decisión es importante cuando varios procesos abren el mismo bloque, sobre todo si se inician de forma independiente.
Una elección incorrecta puede provocar eliminación prematura, avisos de recursos filtrados o segmentos abandonados. En esta guía aprenderás cuándo usar track=True, cuándo usar track=False, cómo definir un propietario, cómo combinar close() y unlink(), y qué cambia entre Linux, macOS y Windows.
Qué es la memoria compartida
La memoria compartida permite que varios procesos accedan a los mismos bytes sin serializar y copiar objetos grandes en cada intercambio. Es útil para matrices numéricas, imágenes, cachés, análisis de datos y servicios de baja latencia.
from multiprocessing import shared_memory
shm = shared_memory.SharedMemory(create=True, size=1024)
try:
shm.buf[:4] = b"PYTH"
finally:
shm.close()
shm.unlink()close() libera el descriptor local. unlink() elimina el nombre del segmento. En sistemas POSIX, los procesos que ya lo abrieron pueden seguir usando sus descriptores, pero nuevos clientes no podrán conectarse. En Windows, el sistema elimina el recurso cuando se cierran todos los identificadores.
Qué hace track
Con track=True, el segmento se registra en el resource tracker. Si un proceso termina sin limpiar, el tracker puede eliminar el recurso. Esto resulta cómodo cuando todos los procesos forman parte de la misma familia creada por multiprocessing.
Con track=False, ese proceso no registra el segmento. La aplicación debe decidir de forma explícita quién es responsable de la limpieza. Este modelo suele ser mejor para procesos iniciados por shells, supervisores, contenedores o servicios distintos.
Procesos independientes
Imagina un productor iniciado por systemd y un consumidor ejecutado manualmente. Si cada uno tiene su propio resource tracker y ambos usan track=True, el primero que termine puede solicitar la eliminación del segmento aunque el otro todavía necesite que nuevos clientes se conecten.
Una arquitectura más segura define un único propietario. El propietario crea el segmento y llama a unlink() al final. Los clientes independientes usan track=False y solo llaman a close().
from multiprocessing import shared_memory
shm = shared_memory.SharedMemory(
name="datos_academify",
create=False,
track=False,
)
try:
contenido = bytes(shm.buf[:128])
finally:
shm.close()Patrón de propietario único
El propietario crea el recurso, publica su nombre, escribe un encabezado de protocolo, coordina lectores y elimina el segmento durante el cierre definitivo. Puede mantener track=True como protección, mientras los clientes externos usan track=False.
from multiprocessing import shared_memory
shm = shared_memory.SharedMemory(
name="cache_python",
create=True,
size=4096,
track=True,
)
try:
shm.buf[:8] = b"CACHE001"
input("Pulsa Enter para cerrar")
finally:
shm.close()
shm.unlink()Así se evita que todos los consumidores intenten borrar el mismo recurso.
Procesos de la misma aplicación
Cuando los workers se crean con multiprocessing.Process, Pool u otra herramienta coordinada por la misma aplicación, track=True suele ser razonable. Aun así, conviene mantener limpieza explícita con try/finally y probar cierres abruptos.
También puedes comparar este modelo con multiprocessing en Python, queue en Python, mmap en Python y memoryview en Python.
close no es unlink
Todos los participantes deben ejecutar close() cuando ya no usan su descriptor. Solo el propietario debería ejecutar unlink(). Si cualquier cliente elimina el nombre, el orden de apagado pasa a controlar la disponibilidad del sistema.
Si existe failover, define cómo se elige un nuevo propietario mediante un lease, archivo de bloqueo, supervisor u otro mecanismo fiable.
Comportamiento en Windows
En Windows, la memoria compartida se elimina cuando se cierran todos los identificadores. Por eso el efecto práctico de track es diferente. Un programa portable no debe asumir que lo observado en Windows será idéntico en Linux. Mantén un modelo de propiedad claro en todas las plataformas.
Formato y validación del buffer
La memoria compartida solo contiene bytes. Guarda un encabezado con versión, longitud, estado y checksum. Antes de leer, valida cada campo.
import struct
version, longitud = struct.unpack_from("!II", shm.buf, 0)
if version != 1:
raise RuntimeError("Versión no compatible")
if longitud > len(shm.buf) - 8:
raise ValueError("Longitud inválida")Para matrices, combina el buffer con memoryview, struct o NumPy, pero verifica dimensiones, tipo y orden de bytes.
La sincronización es independiente
track no bloquea lecturas ni escrituras. Solo controla el rastreo del recurso. Usa locks, semáforos, eventos, colas de control o un protocolo versionado. Un patrón común marca el bloque como “escribiendo”, copia los datos, calcula un checksum y después cambia el estado a “listo”.
Fallos y reinicios
Considera productores que fallan antes de unlink, consumidores que siguen activos y servicios que se reinician. No borres automáticamente un segmento existente: puede pertenecer a otra instancia sana. Usa nombres con aplicación, entorno e identificador de instancia.
En contenedores, revisa el namespace IPC. Dos contenedores pueden no ver el mismo segmento si no comparten la configuración correspondiente.
Pruebas recomendadas
Prueba varios órdenes de cierre: propietario primero, cliente primero, múltiples clientes, finalización forzada y reinicio. Verifica que nuevos clientes puedan conectarse mientras el propietario está activo y que fallen después de un unlink intencional.
Consulta la documentación oficial de shared_memory y la documentación de multiprocessing.
Errores comunes
Los errores frecuentes son permitir que todos llamen a unlink(), usar track=True en procesos no relacionados sin entender trackers separados, olvidar close(), omitir sincronización, confiar en longitudes no validadas y reutilizar nombres fijos.
El resource tracker es una red de seguridad, no un protocolo de propiedad.
Checklist de producción
Define un propietario. Elige track según la topología. Cierra todos los descriptores. Elimina el segmento solo al final correcto. Valida encabezados y tamaños. Sincroniza el acceso. Monitoriza recursos huérfanos. Prueba fallos y reinicios en cada sistema operativo soportado.
Conclusión
El parámetro track no cambia cómo se comparten los bytes; cambia si un proceso pide al resource tracker que participe en la limpieza. Usa track=True en una familia multiprocessing coordinada. Usa track=False en clientes independientes cuando existe un propietario explícito. Con propiedad clara, limpieza correcta, sincronización y validación, la memoria compartida se vuelve rápida y predecible.







