2013-03-02 5 views
12

Я новичок в Python (я из PHP), я читал учебники и пытается вещи в течение нескольких дней, но я не могу понять этот пример очереди (http://docs.python.org/2/library/queue.html)Python потоков и очереди Пример

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 

Я не понимаю, как рабочий поток завершается и существует. Я читал блоки q.get() до тех пор, пока элемент не будет доступен, поэтому, если все элементы обработаны и в очереди не осталось, почему q.get() не блокируется навсегда?

ответ

9

Нити не выходят нормально в этом коде (они действительно заблокированы, когда очередь пуста). Программа не ждет их, потому что они daemon threads.

Программа не выходит сразу и не блокируется навсегда из-за q.join и q.task_done звонков.

Количество незавершенных задач увеличивается, когда элемент добавляется в очередь. Счетчик сбрасывается всякий раз, когда потребительский поток вызывает task_done(), чтобы указать, что элемент был восстановлен, и все работы над ним завершены. Когда количество незавершенных задач падает до нуля, join() разблокирует, и программа существует, не дожидаясь потоков демона.

-3

У меня была та же проблема. Когда все потоки завершены, я видел «спящие потоки» в списке процессов (используйте top -H -p <pid>, где <pid> - это идентификатор процесса от ps aux | grep python с вашим скриптом).

Я решил эту проблему, заменив «бесконечный цикл» while True на while not q.empty():.

Устранена проблема с «спальными нитями».

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

Это решение довольно рискованное. Если рабочие потоки бывают быстрыми, они будут проверять 'q.empty()' до того, как все элементы будут добавлены в очередь, а затем выйдите, прежде чем они что-нибудь сделают. Точно так же, если в очереди остался один элемент, а два потока проверяют 'q.empty()' одновременно, они оба будут продолжаться, но один получит элемент из очереди, а другой будет блокироваться в 'q.get() '. –

Смежные вопросы