Noto que a menudo se sugiere usar colas con múltiples hilos, en lugar de listas y .pop()
. ¿Es esto porque las listas no son seguras para subprocesos o por alguna otra razón?
155
Noto que a menudo se sugiere usar colas con múltiples hilos, en lugar de listas y .pop()
. ¿Es esto porque las listas no son seguras para subprocesos o por alguna otra razón?
Respuestas:
Las listas en sí son seguras para subprocesos. En CPython, el GIL protege contra accesos concurrentes a ellos, y otras implementaciones se encargan de usar un bloqueo de grano fino o un tipo de datos sincronizado para sus implementaciones de listas. Sin embargo, si bien las listas en sí no pueden corromperse por intentos de acceso simultáneo, los datos de las listas no están protegidos. Por ejemplo:
no se garantiza que aumente L [0] en uno si otro hilo hace lo mismo, porque
+=
no es una operación atómica. (Muy, muy pocas operaciones en Python son realmente atómicas, porque la mayoría de ellas pueden provocar que se invoque un código arbitrario de Python). Debería usar Colas porque si solo usa una lista desprotegida, puede obtener o eliminar el elemento incorrecto debido a la raza condicionesfuente
Para aclarar un punto en la excelente respuesta de Thomas, debe mencionarse que
append()
es seguro para subprocesos.Esto se debe a que no hay preocupación de que los datos que se leen estarán en el mismo lugar una vez que lo escribamos . La
append()
operación no lee datos, solo escribe datos en la lista.fuente
PyList_Append
se realiza en un bloqueo GIL. Se le da una referencia a un objeto para agregar. El contenido de ese objeto puede cambiarse después de que se evalúa y antes de quePyList_Append
se realice la llamada . Pero seguirá siendo el mismo objeto y se agregará de forma segura (si lo hacelst.append(x); ok = lst[-1] is x
,ok
puede ser falso, por supuesto). El código al que hace referencia no lee del objeto adjunto, excepto para INCREMENTARLO. Lee y puede reasignar la lista a la que se agrega.L[0] += x
realizará un__getitem__
encendidoL
y luego un__setitem__
encendidoL
; si esL
compatible__iadd__
, hará las cosas un poco diferente en la interfaz del objeto, pero todavía hay dos operaciones separadasL
en el nivel de intérprete de Python (las verá en el bytecode compilado). Elappend
se realiza en una llamada de método único en el código de bytes.remove
?Aquí hay una lista completa pero no exhaustiva de ejemplos de
list
operaciones y si son seguros o no para subprocesos. Con la esperanza de obtener una respuesta con respecto a laobj in a_list
construcción del lenguaje aquí .fuente
Recientemente tuve este caso en el que necesitaba agregar una lista continuamente en un hilo, recorrer los elementos y verificar si el elemento estaba listo, en mi caso era un AsyncResult y eliminarlo de la lista solo si estaba listo. No pude encontrar ningún ejemplo que demostrara mi problema claramente. Aquí hay un ejemplo que demuestra agregar a la lista en un hilo continuamente y eliminar de la misma lista en otro hilo continuamente. unas pocas veces y verás el error
La versión defectuosa
Salida cuando ERROR
Versión que usa cerraduras
Salida
Conclusión
Como se mencionó en las respuestas anteriores, mientras que el acto de agregar o extraer elementos de la lista es seguro para subprocesos, lo que no es seguro para subprocesos es cuando se agrega en un subproceso y aparece en otro
fuente
with r:
) en lugar de llamar explícitamenter.acquire()
yr.release()