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
循环。
以下成功退出时挂起
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
循环。