Thread Safety nel dizionario di Python


105

Ho una classe che contiene un dizionario

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

E sto eseguendo 4 thread (uno per ogni ristorante) che chiamano il metodo OrderBook.addOrder. Ecco la funzione eseguita da ogni thread:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

È sicuro o devo usare un lucchetto prima di chiamare addOrder?


2
come potrebbe esserci un problema quando ogni thread scrive comunque su una chiave diversa.
Jochen Ritzel

64
@ Jochen: a seconda di come vengono implementati i dict, molto potrebbe andare storto. Questa è una domanda molto ragionevole.
Ned Batchelder

Risposte:


95

Le strutture integrate di Python sono thread-safe per singole operazioni, ma a volte può essere difficile vedere dove un'istruzione diventa davvero più operazioni.

Il tuo codice dovrebbe essere al sicuro. Tieni presente: un lucchetto qui non aggiungerà quasi nessun sovraccarico e ti darà la massima tranquillità.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm contiene maggiori dettagli.


6
Ecco il perché / come fare di effbot.org sull'implementazione di una serratura
piani di cottura

1
Dovrebbe prendere in considerazione un'operazione singola rispetto a operazioni composite, come get-add-set .
andy

5
il problema è che, quando leggo / scrivo spesso quel dict, quella tranquillità mi costerà molto.
Shihab Shahriar Khan

2
"un lucchetto qui non aggiungerà quasi nessun overhead": perché?
max

32

Sì, i tipi incorporati sono intrinsecamente thread-safe: http://docs.python.org/glossary.html#term-global-interpreter-lock

Ciò semplifica l'implementazione di CPython rendendo il modello a oggetti ( inclusi i tipi incorporati critici come dict ) implicitamente sicuro contro l'accesso simultaneo.


25
Questa non è una caratteristica di Python, ma di cpython .
phihag

8
Vero, ma a quanto ho capito, i built-in in Jython e IronPython sono anche thread-safe anche senza l'uso del GIL (e la rondine a vuoto, se dovesse mai emergere, propone di eliminare anche il GIL). Ho pensato che, poiché non ha specificato l'interprete che stava usando, intendesse in CPython.

1
Corretto nel caso di Jython: jython.org/jythonbook/en/1.0/…
Evgeni Sergeev

9

La guida di stile di Google sconsiglia di fare affidamento sull'atomicità dei dettami

Spiegato in maggiore dettaglio in: L' assegnazione di variabili Python è atomica?

Non fare affidamento sull'atomicità dei tipi incorporati.

Mentre i tipi di dati incorporati di Python come i dizionari sembrano avere operazioni atomiche, ci sono casi d'angolo in cui non sono atomici (ad esempio se __hash__o __eq__sono implementati come metodi Python) e la loro atomicità non dovrebbe essere invocata. Né dovresti fare affidamento sull'assegnazione di variabili atomiche (poiché questo a sua volta dipende dai dizionari).

Utilizzare il Queuetipo di dati Queue del modulo come metodo preferito per comunicare i dati tra i thread. Altrimenti, usa il modulo di threading e le sue primitive di blocco. Informazioni sull'uso corretto delle variabili di condizione in modo da poterle utilizzare threading.Conditioninvece di utilizzare blocchi di livello inferiore.

E sono d'accordo con questo: c'è già il GIL in CPython, quindi il successo delle prestazioni dell'utilizzo di un Lock sarà trascurabile. Molto più costose saranno le ore trascorse a cercare bug in una complessa base di codice quando i dettagli di implementazione di CPython cambieranno un giorno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.