ProgramaciónDesarrollador de Python

¿Qué sucede al pasar objetos compuestos (por ejemplo, listas de diccionarios) entre hilos o procesos en Python? ¿Qué es importante recordar al programar aplicaciones multihilo y multiproceso relacionadas con colecciones mutables?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En Python, al trabajar con hilos, los objetos en memoria están disponibles para todos los hilos sin copia. Sin embargo, al trabajar con procesos a través de multiprocessing, los objetos estándar de Python (como listas y diccionarios) se transfieren entre procesos mediante serialización (generalmente a través de pickle), y cada proceso recibe su propia copia del objeto. Los cambios en el objeto en un proceso no se reflejan en la copia en otro proceso.

Diferencias clave:

  • Multihilo (threading): Todos los hilos trabajan en el mismo espacio de direcciones. Cualquier objeto (incluidas las colecciones anidadas) se comparte.
  • Multiproceso (multiprocessing): Cada proceso tiene su propia memoria; los objetos se transfieren a través de serialización. Para el intercambio entre procesos, se deben utilizar estructuras especiales, por ejemplo, multiprocessing.Manager().dict().

Ejemplo:

# Multiprocesamiento from multiprocessing import Process, Manager def worker(d): d['a'] = 42 if __name__ == '__main__': # Un dict simple no funciona entre procesos managed_dict = Manager().dict() p = Process(target=worker, args=(managed_dict,)) p.start(); p.join() print(managed_dict['a']) # 42
  • Si se usara un dict normal, los cambios en el proceso no serían visibles en el proceso principal.

Pregunta engañosa.

¿En qué casos la edición de una lista normal (list) en un proceso se reflejará en otro proceso?

Respuesta:

Nunca, si se trabaja con multiprocessing. Los objetos normales de Python no se comparten entre procesos. Para compartir, se deben utilizar primitivas especiales: objetos Manager (por ejemplo, Manager().list(), Manager().dict()), que sincronizan el estado entre procesos.

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

Un equipo de desarrolladores de un rastreador web inicializó colas de tareas como listas y las dividió entre procesos a través de multiprocessing. Las tareas "se perdían" porque los procesos no veían las actualizaciones de los demás. Se corrigió utilizando Manager().list().


Historia

En un servicio analítico, intentaron recopilar registros en diccionarios anidados dentro de los hilos. En un escenario de alta carga, esto llevó a una condición de carrera y corrupción de datos debido a la falta de bloqueos.


Historia

En un servicio ETL, al intentar recopilar objetos de datos recopilados durante la etapa de procesamiento en múltiples procesos, se descubrió duplicación/pérdida de datos: los programadores no tuvieron en cuenta que cada proceso trabajaba con su propia copia de la estructura, y no con una común.