我有一个队列和一个事件。我想在事件设置为True时退出循环,但是循环中有一个queue.get()阻塞,直到有东西。
当设置closeEvent Event标志时,如何中止self._commandQueue.get()的等待?
注意:我想避免依赖队列的阻塞性质,并希望根据队列条件和事件标志进行阻止
def _execute(self):
while not self._closeEvent.isSet():
nextCommand = self._commandQueue.get()
self._commandExecutor.execute(nextCommand)
self._commandQueue.task_done()
答案 0 :(得分:3)
Queue
根据内部使用事件
http://hg.python.org/cpython/file/3a1db0d2747e/Lib/Queue.py#l150具体来说,它使用了self.not_empty事件,您的应用程序也可以在尝试Queue.get_nowait
调用之前等待。
至于等待几个事件的Python threading: can I sleep on two threading.Event()s simultaneously?问题和一些代码示例。
答案 1 :(得分:3)
你需要类似Windows WaitForMultipleObjects()
调用的东西,但是python事件和队列API不提供这样的野兽(但是你可以使用win32api来使用它,如果你是严格的窗口),所以如果您确实需要同时检查两个事件来源,答案是“如果没有轮询(或猴子修补事件类以允许它),就不能这样做”。
但是如果你更灵活,你可以通过重新定义命令队列来安排类似的东西。如果命令队列是PriorityQueue
,您可以按正常优先级排序正常作业,并有一个额外的进程队列a' STOP'一旦您的事件发出信号,优先级更高的令牌。
STOP = None
def _execute(self):
while 1:
nextCommand = self._commandQueue.get()[1]
if nextCommand is STOP:
break
self._commandExecutor.execute(nextCommand)
self._commandQueue.task_done()
def wait_for_stop_signal(self):
self._closeEvent.wait()
self._commandQueue.put((-1, STOP))
现在你在自己的线程中运行wait_for_stop_signal
,并且你有自己想要的行为(但是浪费一个线程而不是轮询,为你的用例选择更糟糕的事情。)
答案 2 :(得分:2)
我提供这两种选择,可能适合:
将“魔术退出标记”放入队列中。我将使用None,如果需要,您可以使用特殊的Quit消息。这与使用优先级队列方法大致相同,但是(a)它稍微简单一点,(b)但是队列必须清空标记点,这可能是你可能接受的,也可能是不可接受的。 / p>
例如:
# Untested
# Processing thread
def run(self):
while True:
msg = self.main_queue.get()
if msg == None:
break
...do..queue..work...
def shutdown():
self.main_queue.put(None)
而不是马上调用Queue.get。创建一个在以下任一情况下发出信号的事件对象: *有些东西被放入队列中。 *你想关机
不要将队列暴露给外部世界,而是定义一个添加到队列的方法:
def add_to_queue(self, msg):
self.main_queue.put(msg)
self.my_event.set() # Signal the consumer
def shutdown(self, msg):
self.quit_event.set() # Set an event / condvar / msg to indicate exit
self.my_event.set() # Signal something has happened.
def run(self)
while True:
self.my_event.wait()
if self.quit_event.is_set()
break
msg = self.main_queue.get(False) # Empty exception should not happen here
您不一定需要退出事件,因为您可以假设一个空队列,并且发出信号my_event意味着它是时候退出了。虽然,我认为最好明确使用正确的指标 - 消息,事件,条件变量等
答案 3 :(得分:0)
Queue.get
是一种在没有参数的情况下调用的阻塞方法。
来自docs:
将项目放入队列。如果可选的args块为true且超时为 无(默认值),必要时阻止,直到有空闲插槽可用。 如果timeout是一个正数,它最多会阻塞超时秒数 如果其中没有可用的空闲插槽,则引发完全例外 时间。否则(块为假),如果有空,则将项目放在队列中 slot立即可用,否则引发Full异常(超时 在这种情况下被忽略。)
您需要做类似的事情:
try:
# If `False`, the program is not blocked, it will throw the Queue.Empty exception.
my_data = queue.get(False)
.....Some Code......
except Queue.Empty:
my_data = None # or whatever you want
更多选项
get_nowait :
Queue.get_nowait()
相当于get(False)
。
使用超时:
my_data = queue.get(True,5)
如果get将失败(没有得到),这将尝试获得5个secends它将引发相同的异常Queue.Empty