Ho un'applicazione che sta acquisendo un blocco in un loop in un thread per eseguire alcune attività. C'è anche una seconda discussione che vuole anche acquisire il blocco da di volta in volta. Il problema è che questo secondo thread ottiene a malapena l'opportunità di eseguire il lavoro , in quanto il primo quasi sempre si blocca per primo. Mi auguro che il seguente codice di chiarirà quello che sto cercando di dire:Thread starvation mentre si blocca un loop in Python
import time
from threading import Lock, Thread
lock = Lock()
def loop():
while True:
with lock:
time.sleep(0.1)
thread = Thread(target=loop)
thread.start()
before = time.time()
lock.acquire()
print('Took {}'.format(time.time() - before))
Se l'applicazione arriva a print
si noterà che aveva bisogno di molto più di solo 0,1 s. Ma a volte capita anche che aspetti solo indefinitamente. Ho testato questo sia in Python 2.7.11 che in Python 3.4.3 su Debian Linux 8 e funziona in modo identico.
Questo comportamento è controintuitivo per me. Dopo tutto, quando il blocco è stato rilasciato in loop
, lo lock.acquire
era già in attesa della sua versione e dovrebbe acquisire immediatamente il blocco. Ma sembra che il ciclo acquisisca prima il blocco , anche se non era in attesa del suo rilascio nel momento di rilascio .
La soluzione che ho trovato è di dormire tra ogni iterazione del ciclo in stato sbloccato, ma che non mi sembra una soluzione elegante, essa non spiegarmi cosa è accadendo.
Cosa mi manca?
Se si desidera un comportamento deterministico anziché un'esclusione reciproca, allora 'Lock' non è l'oggetto giusto da usare. Potresti essere in grado di forzare un cambio di attività emettendo un' time.sleep (0) 'ma io sono certo che fallirebbe su alcune piattaforme .. – thebjorn
Bene, ho capito che quando ho solo due thread, quando uno aspetta un lock, lo otterrà sempre dopo che l'altro si sblocca. Quello che mi chiedo è perché non sia così. Inoltre, cosa pensi che sarebbe un oggetto appropriato da usare? –
Difficile dire perché stia accadendo, ma se dovessi indovinare sarebbe qualcosa che ha a che fare con i commutatori di attività in modo tale che il ciclo while riesca a richiamare di nuovo aquire prima che il codice relase abbia raggiunto il punto in cui seleziona tra i thread in attesa. Ma questo è solo indovinare. – thebjorn