2013-03-02 21 views
12

Jestem nowy python (I pochodzić z PHP), czytałem tutoriale i próbuje rzeczy na kilka dni, ale nie mogę zrozumieć ten przykład kolejki (http://docs.python.org/2/library/queue.html)Python wątków i kolejka przykład

def worker(): 
    while True: 
     item = q.get() 
     do_work(item) 
     q.task_done() 

q = Queue() 
for i in range(num_worker_threads): 
    t = Thread(target=worker) 
    t.daemon = True 
    t.start() 

for item in source(): 
    q.put(item) 

q.join()  # block until all tasks are done 

Rzeczą, której nie rozumiem, jest to, w jaki sposób wątek roboczy się kończy i istnieje. Czytałem bloki q.get(), dopóki element nie jest dostępny, więc jeśli wszystkie elementy są przetwarzane i żadna nie pozostanie w kolejce, dlaczego q.get() nie blokuje na zawsze?

Odpowiedz

9

Wątki nie kończą się normalnie w tym kodzie (są rzeczywiście blokowane, gdy kolejka jest pusta). Program nie czeka na nich, ponieważ są one daemon threads.

Program nie kończy się natychmiast i nie blokuje na zawsze z powodu połączeń q.join i q.task_done.

Liczba nieukończonych zadań wzrasta po dodaniu elementu do kolejki. Liczba ta spada, gdy wątek konsumencki wywołuje task_done(), aby wskazać, że element został pobrany, a wszystkie prace nad nim zakończone. Gdy liczba niedokończonych zadań spadnie do zera, odblokuje się join(), a program istnieje bez czekania na wątki demona.

-3

Miałem ten sam problem. Po zakończeniu wszystkich wątków zobaczyłem listę wątków na liście procesów (użyj top -H -p <pid>, gdzie <pid> jest identyfikatorem procesu z ps aux | grep python ze skryptem).

Rozwiązałem ten problem, zastępując "nieskończoną pętlę" while True na while not q.empty():.

Naprawiono problem z "zasypianiem wątków".

def worker(): 
    while not q.empty(): 
     item = q.get() 
     do_work(item) 
     q.task_done() 

q = Queue() 
for i in range(num_worker_threads): 
    t = Thread(target=worker) 
    t.daemon = True 
    t.start() 

for item in source(): 
    q.put(item) 

q.join()  # block until all tasks are done 
+0

To rozwiązanie jest dość ryzykowne. Jeśli wątki robocze są szybkie, przetestują 'q.empty()' zanim jakiekolwiek elementy zostaną dodane do kolejki, a następnie zakończą zanim coś zrobią. Podobnie, jeśli w kolejce pozostanie pojedyncza pozycja, a dwa wątki testują jednocześnie 'q.empty()', oba będą kontynuowane, ale jeden z nich wyjdzie z kolejki, a drugi zablokuje na 'q.get() '. –