Recientemente escribí un programa que usaba un patrón simple de productor/consumidor. Inicialmente tenía un error relacionado con el uso incorrecto de subprocesos. Bloqueo que finalmente arreglé. Pero me hizo pensar si es posible implementar el patrón de productor/consumidor de una manera sin cerraduras.¿Este enfoque de Python productor-consumidor sin bloqueo es seguro para subprocesos?
Requisitos en mi caso eran simples:
- Un hilo productor.
- Un hilo de consumo.
- Queue tiene lugar para un solo artículo.
- El productor puede producir el siguiente artículo antes de que se consuma el actual. El artículo actual se pierde, pero eso está bien para mí.
- El consumidor puede consumir el artículo actual antes de que se produzca el siguiente. Por lo tanto, el artículo actual se consume dos veces (o más), pero eso está bien para mí.
Así que escribió esto:
QUEUE_ITEM = None
# this is executed in one threading.Thread object
def producer():
global QUEUE_ITEM
while True:
i = produce_item()
QUEUE_ITEM = i
# this is executed in another threading.Thread object
def consumer():
global QUEUE_ITEM
while True:
i = QUEUE_ITEM
consume_item(i)
Mi pregunta es: ¿Es este código flujos seguros?
Comentario inmediato: este código no es realmente sin cerrojo: uso CPython y tiene GIL.
He probado el código un poco y parece funcionar. Se traduce en algunas operaciones LOAD y STORE que son atómicas debido a GIL. Pero también sé que el funcionamiento de del x
no es atómico cuando x implementa el método __del__
. Entonces, si mi artículo tiene un método __del__
y ocurre una programación desagradable, las cosas pueden romperse. ¿O no?
Otra pregunta es: ¿Qué tipo de restricciones (por ejemplo, en el tipo de elementos producidos) debo imponer para que el código anterior funcione bien?
Mis preguntas son solo acerca de la posibilidad teórica de explotar los caprichos de CPython y GIL para llegar a una solución sin cerraduras (es decir, no bloquea como el enhebrado. Bloqueo explícito en el código).
¿Por qué escribirías un método __del__? –