Ho recentemente scritto un programma che utilizzava un semplice pattern produttore/consumatore. Inizialmente aveva un bug relativo all'utilizzo improprio del threading.Lock che alla fine ho risolto. Ma mi ha fatto pensare se è possibile implementare il modello produttore/consumatore in un modo senza blocco.Questo approccio lockless consumer-consumer Python è thread-safe?
Requisiti nel mio caso erano semplici:
- Un thread produttore.
- Un thread di consumo.
- La coda ha posto per un solo articolo.
- Il produttore può produrre l'elemento successivo prima che venga consumato quello corrente. L'oggetto attuale è quindi perso, ma va bene per me.
- Il consumatore può consumare l'articolo corrente prima che venga prodotto quello successivo. L'oggetto corrente viene quindi consumato due volte (o più), ma per me va bene.
Così ho scritto questo:
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)
La mia domanda è: E 'questo codice thread-safe?
Commento immediato: questo codice non è veramente privo di blocco - Io uso CPython e ha GIL.
Ho testato il codice un po 'e sembra funzionare. Si traduce in alcune operazioni LOAD e STORE che sono atomiche a causa di GIL. Ma so anche che l'operazione del x
non è atomica quando x implementa il metodo __del__
. Quindi, se il mio articolo ha un metodo __del__
e accade qualche brutto scheduling, le cose potrebbero rompersi. O no?
Un'altra domanda è: che tipo di restrizioni (ad esempio sul tipo di articoli prodotti) devo imporre per far funzionare correttamente il codice sopra?
Le mie domande riguardano solo la possibilità teorica di sfruttare le stranezze di CPython e GIL per ottenere soluzioni senza lock (cioè senza serrature come threading.Lock esplicitamente nel codice).
Perché dovresti scrivere un metodo __del__? –