Python等待队列和事件

时间:2014-08-04 10:47:35

标签: python multithreading python-2.7 multiprocessing

我有一个队列和一个事件。我想在事件设置为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()

4 个答案:

答案 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)

我提供这两种选择,可能适合:

解决方案1 ​​

将“魔术退出标记”放入队列中。我将使用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)

解决方案2

而不是马上调用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

更多选项

  1. get_nowait

    Queue.get_nowait()

    相当于get(False)

  2. 使用超时

    my_data = queue.get(True,5)

    如果get将失败(没有得到),这将尝试获得5个secends它将引发相同的异常Queue.Empty