2012-12-11 151 views
0

假設我有一個線程池。這個線程池使用兩個隊列q1q2。它從q1讀取並在q2上寫入新項目。當q1爲空時,我們交換兩個隊列q1, q2, = q2, q1,我們重複該過程,直到兩者都爲空。爲了同步線程,我使用另一個只包含一個項目的隊列,並在流程結束時刪除此項目。使用兩個隊列同步線程

我認爲這是一個非常愚蠢的做法。任何改進建議?

一個非常漂亮的簡單例子是docs,但只有一個隊列。我的解決方案看起來並不很漂亮,如果是正確的:

global flag 
global lock 
global barrier 
global q1 
global q2 
global q 
while True: 
    if q1.empty(): 
     flag = False 
     barrier.wait() # wait for all the theads to reach this point. 
     # execute the code of swapping queues only once 
     with lock: 
      if not flag: 
       flag = True 
       if q2.empty(): 
        q.get() 
        q.task_done() 
       else: 
        q1, q2 = q2, q1 

    process_items_in_q1() 
+2

您正在使用2個輸入隊列的原因嗎?如果你有一個工作者線程池,爲什麼沒有一個輸入隊列讓工作者從中獲得工作?先進先出?雙輸入隊列是否是一項要求? – user1836293

+0

我正在實施BFS +我們發現的每個節點的一些東西。每個階段的seaching可以並行化,但是當一個階段完成後,纔可以轉到下一個階段。當然,除非我錯過了一個更好的主意。 –

回答

0

我覺得你的aproach工作。這裏有兩個人,你可能會或可能不會找到更好:

  1. 只能使用一個隊列,推動N種標記分離的「級別」,其中N是線程數。當線程讀取標記時,它只會調用barrier.wait()。如果目標僅僅是確保所有N個線程在關卡之間調用barrier.wait(),那麼這應該足夠了。

  2. 或者,您可以簡化上述代碼:使用2個普通列表而不是2個隊列。所有線程從list1彈出並附加到list2,這不需要隊列邏輯中的特殊照顧。另外,如果「levels」每個都相對較大,那麼可以簡單地爲每個級別重複創建線程的整個代碼,並等待它們全部完成。這將使得一個時間一個一個的邏輯更加明顯。

(最後,像往常一樣,請注意,到目前爲止,你不要在Python中使用線程獲得任何的處理能力。還有的GIL)

+0

感謝您的輸入! 標記的替代解決方案應該是等效的。我最好的猜測是具有task_done的隊列機制可以抽象出障礙。我沒有看過它。 至於列表,他們實施低效率的'pop()'操作。至於GIL,我的process_items是I/O綁定的,所以線程正常。 –

+0

對不起,我記住'list1.pop()'沒有參數,即彈出列表的最後一個元素(這是有效的)。如果需要的話,你可以在從list1移動到list2時將列表反轉()。或者使用'collection.deque'。 –