Condividere i dati in sicurezza
Usare code e lock
Condividere i dati in sicurezza è una lezione Python Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Python Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Python Academy include 4 lezioni in totale.
Il problema delle race condition
Quando più thread modificano gli stessi dati, le loro operazioni possono intercalarsi e corrompere il risultato. Questa è una race condition. Servono strumenti di sincronizzazione per condividere i dati in modo sicuro.
import threading
counter = 0
def bump():
global counter
for _ in range(100000):
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter (may be < 200000):', counter)Lock in soccorso
Un threading.Lock garantisce che un solo thread alla volta entri in una sezione critica. Lo acquisisca usando un blocco with attorno all'aggiornamento condiviso.
import threading
counter = 0
lock = threading.Lock()
def bump():
global counter
for _ in range(100000):
with lock:
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter:', counter)acquire e release
Un lock può essere usato manualmente con acquire() e release(), ma la forma with è più sicura perché rilascia il lock anche se si verifica un errore.
import threading
lock = threading.Lock()
lock.acquire()
try:
print('inside critical section')
finally:
lock.release()
print('released')Code thread-safe
La classe queue.Queue è già thread-safe. I thread possono eseguire put e get senza lock espliciti, quindi questa è la modalità preferita per passare i dati.
import queue, threading
q = queue.Queue()
def producer():
for i in range(3):
q.put(i)
t = threading.Thread(target=producer)
t.start()
t.join()
while not q.empty():
print('got', q.get())Produttore e consumatore
Il modello classico: i produttori inseriscono il lavoro nella coda con put, mentre i consumatori lo recuperano con get e lo elaborano. La coda gestisce tutti i lock.
import queue, threading
q = queue.Queue()
results = []
def consumer():
while True:
item = q.get()
if item is None:
break
results.append(item * 10)
q.task_done()
t = threading.Thread(target=consumer)
t.start()
for i in range(3):
q.put(i)
q.put(None)
t.join()
print(results)join e task_done
q.join() blocca l'esecuzione finché ogni elemento inserito con put non ha ricevuto una chiamata corrispondente a task_done(). In questo modo il thread principale può attendere il completamento di tutto il lavoro.
import queue, threading
q = queue.Queue()
def worker():
while True:
item = q.get()
q.task_done()
threading.Thread(target=worker, daemon=True).start()
for i in range(5):
q.put(i)
q.join()
print('all items processed')RLock per la rientranza
Un normale Lock causa un deadlock se lo stesso thread tenta di acquisirlo due volte. Un threading.RLock (lock rientrante) lo consente, tenendo conto del numero di acquisizioni.
import threading
rlock = threading.RLock()
def outer():
with rlock:
inner()
def inner():
with rlock:
print('re-entered safely')
outer()Event per la segnalazione
Un threading.Event consente a un thread di inviare un segnale agli altri. I thread chiamano wait() finché un altro non chiama set().
import threading
start = threading.Event()
def worker():
start.wait()
print('go!')
t = threading.Thread(target=worker)
t.start()
print('setting event')
start.set()
t.join()Condivisione tra processi
Tra processi, usi invece multiprocessing.Queue. Questa serializza gli oggetti tra spazi di memoria separati.
import multiprocessing as mp
def producer(q):
for i in range(3):
q.put(i * i)
if __name__ == '__main__':
q = mp.Queue()
p = mp.Process(target=producer, args=(q,))
p.start()
p.join()
while not q.empty():
print('received', q.get())Evitare i deadlock
Si verifica un deadlock quando i thread attendono per sempre i lock degli altri. Lo eviti acquisendo sempre più lock nello stesso ordine, in ogni punto del programma.
import threading
lock_a = threading.Lock()
lock_b = threading.Lock()
def safe():
with lock_a:
with lock_b:
print('acquired in consistent order')
safe()Preferire le code ai lock
Quando possibile, preferisca il passaggio di messaggi tramite code allo stato mutabile condiviso protetto da lock. È più facile da comprendere e presenta molti meno rischi di bug.
import queue
q = queue.Queue()
for word in ['safe', 'simple', 'clear']:
q.put(word)
while not q.empty():
print(q.get())Verifica rapida
Verifichi la Sua comprensione della condivisione sicura dei dati.
Ripasso
Ha imparato a condividere i dati in modo sicuro:
- Le race condition corrompono lo stato condiviso non protetto.
LockeRLockproteggono le sezioni critiche.queue.Queueè thread-safe; usimultiprocessing.Queuetra processi.Eventinvia segnali tra thread; un ordine coerente dei lock evita i deadlock.
Prossimo corso: eseguire programmi esterni con subprocess.
Domande Frequenti
La lezione «Condividere i dati in sicurezza» è gratuita?
Sì — il testo completo di «Condividere i dati in sicurezza» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Python Academy, passa a CoddyKit PRO. Il corso Python Academy include 4 lezioni in totale.
Cosa imparerò in «Condividere i dati in sicurezza»?
Usare code e lock Eserciti Python Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Python Academy?
Non è richiesta alcuna esperienza precedente. Python Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Condividere i dati in sicurezza»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Python Academy?
Sì. Ogni lezione Python Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Thread e GIL
- ThreadPoolExecutor
- Nozioni di base su multiprocessing
- Condividere i dati in sicurezza