Python 解释器挂起 - 试验线程和队列

Python interpreter hangs - experimenting with thread and queues

以下成功退出时挂起

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 是仍在运行和挂起的那个,并且试图理解为什么因为我确实发出停止事件信号。我期待循环会退出。

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

感谢帮助!!

您在调用 get 时将 block 设置为 True,这意味着它将阻塞,直到队列中实际有一个项目可用。在您的代码中,一旦工作队列耗尽,下一个 get 将无限期阻塞,因为它正在等待一个永远不会到来的额外工作项(并且不让 while 循环的下一次迭代执行,因此不再检查 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 最终设置时循环将自行中断。

其他选项是调用 get 并将 block 设置为 False 或使用 try/[=27 中的 get_nowait 方法=]块:

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

虽然这会在队列为空时创建一个非常紧凑的 while 循环。