2015-01-07 40 views
0

成功嘗試之後掛在口Python解釋器掛起 - 與線程和隊列

import threading 
import Queue as queue 
import time 
import sys 

class WorkItem(threading.Thread): 

    def __init__(self): 
     self.P1 = 20 
     self.P2 = 40 

     threading.Thread.__init__(self) 

    def run(self): 
     print "P1 = %d" % (self.P1) 
     print "P2 = %d" % (self.P2) 

class WorkQueue(object): 
    def __init__(self,queueLimit = 5): 

     self.WorkQueue = queue.Queue(queueLimit) 
     self.dispatcherThread = threading.Thread(target=self.DequeueWorker) 
     self.dispatcherThread.start() 
     self.QueueStopEvent = threading.Event() 
     self.QueueStopEvent.clear() 

    def DequeueWorker(self): 
     print "DequeueWorker Enter .." 
     while not self.QueueStopEvent.isSet(): 
      workItem = self.WorkQueue.get(True) 
      workItem.start() 

    def DispatchToQueue(self,workItem): 

     self.WorkQueue.put(workItem,True) 

    def Stop(self): 
     self.QueueStopEvent.set() 
     self.queue = None 


def main(): 
    q = WorkQueue() 
    for i in range(1,20): 
     t = WorkItem() 
     q.DispatchToQueue(t) 

    time.sleep(10) 
    q.Stop() 



if __name__ == "__main__": 
    main() 

我可以看到DequeueWorker是一個仍在運行和正在申請,並試圖瞭解爲什麼,因爲我做信號Stop事件。我期待循環會退出。

>>> $w 
=> Frame id=0, function=DequeueWorker 
    Frame id=1, function=run 
    Frame id=2, function=__bootstrap_inner 
    Frame id=3, function=__bootstrap 

幫助讚賞!

回答

1

你打電話getblock設置爲True,這意味着它將阻塞,直到一個項目實際上在隊列中可用。在您的代碼中,一旦工作隊列耗盡,下一個get將無限期阻止,因爲它正在等待永遠不會到來的額外工作項目(並且不會執行下一個迭代循環,所以QueueStopEvent的狀態不會執行,再次檢查)。嘗試修改您的DequeueWorker方法是:

def DequeueWorker(self): 
    print "DequeueWorker Enter .." 
    while not self.QueueStopEvent.isSet(): 
     try: 
      workItem = self.WorkQueue.get(True, timeout=3) 
      workItem.start() 
     except queue.Empty: continue 

現在,當get被稱爲工作隊列耗盡後,它會超時(在這種情況下,在3秒鐘後,我選擇了任意),提高queue.Empty例外。在這種情況下,我們只是讓循環繼續下一次迭代,在最終設置QueueStopEvent時,循環將自行破壞。

其他選項。將調用getblock設置爲False或使用get_nowait方法try/except塊內:

workItem = self.WorkQueue.get(False) 
workItem = self.WorkQueue.get_nowait() 

雖然創建非常緊while環路當隊列是空的。

+0

不應該在這種情況下獲得堆棧調用的頂部,因爲我只能看到幀ID = 0,函數= DequeueWorker作爲調試時的第一幀 – Addy

+0

@Addy我不能說你特定的調試解決方案正在使用,但我知道如果我在'get'調用之前和之後插入'print'語句,清楚地說明在隊列耗盡後'get'永遠不會返回(並且第二個'print'語句不會執行)。 – rchang

+0

這是一個Visual Studio python工具,它也是相同的pdb – Addy