2017-02-22 50 views
1

Python的3文檔給一個使用隊列(https://docs.python.org/3/library/queue.html)一個工作線程的示例:何時需要Queue.join()?

def worker(): 
    while True: 
     item = q.get() 
     if item is None: 
      break 
     do_work(item) 
     q.task_done() 

q = queue.Queue() 
threads = [] 
for i in range(num_worker_threads): 
    t = threading.Thread(target=worker) 
    t.start() 
    threads.append(t) 

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

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

# stop workers 
for i in range(num_worker_threads): 
    q.put(None) 
for t in threads: 
    t.join() 

在這個例子中,爲什麼是必要q.join()?在後續的q.put(None)t.join()操作完成阻塞主線程的同一事情之後,直到工作線程完成?

回答

1

下面是我對這個例子的理解。

每個工人無限循環,總是從隊列中尋找新的東西。如果它獲得的項目是None,它會中斷並將控制權返回給main。

所以,首先我們讓程序等待Queue爲空。對q.task_done()的每個呼叫標記爲完整的新項目。代碼掛在下面,所以我們確保每個項目被標記爲完成。

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

然後,下面,我們增加相同數量的None物品放入隊列中有工人(所以我們要確保每個工人得到一個。)

for i in range(num_worker_threads): 
    q.put(None) 

接下來,我們同所有的線程。由於我們通過隊列給每個工人一個None物品,他們將全部中斷。在他們全部休息並返回控制權之前,我們想要在這裏停留。

for t in threads: 
    t.join() 

這樣做,這樣,我們確保在隊列中的每個項目的處理,每一個工人休息時隊列爲空,每個工人關閉我們繼續與我們的代碼之前,幫助避免孤兒流程。

+0

這幾乎是我對這個例子的解釋。所以,我的問題是,即使我們刪除'q.join()'語句,是不是處理了隊列中的每個項目(並清除了所有線程)?通過加入所有的工作線程(最後一步),我們仍然在等待隊列中的所有項目進行處理。 – SMX

+1

是的,我們仍在等待,但我認爲這是一種編碼安全措施。如果在處理隊列中的所有項目並且工人拿到一個之前添加了'None(無)'奇蹟般地添加了什麼?我認爲這只是一個枯燥程序化的例子,要確保你理解發生的事情,而不必完全理解隊列變爲FIFO(先入先出)。此外,這個例子可以適用於LIFO(Last In First Out)實施。但是,就目前的這個例子而言,我相信你可以取出'q.join()'而且沒關係。 – jarcobi889