.join for python中可能的空队列

时间:2016-07-20 15:20:26

标签: python multithreading python-3.x blockingqueue

我试图在python中实现Queue处理线程,如下所示:

from queue import Queue
from threading import Thread
import sys    

class Worker(Thread):
    def __init__(self, queue):
        # Call thread constructor
        self.queue = queue

    def run(self):
        while True:
            task = self.queue.get()
            # doTask()
            self.queue.task_done()

queue = Queue()
thread = Worker(thread)
thread.start()

while True:
    inp = user_input()

    if condition(inp):
        queue.put(sometask())
    else:
        queue.join()
        thread.join()
        sys.exit(0)

在此示例中,假设用户在未添加任何项目的情况下决定exit。然后,我的帖子将在self.queue.get处阻止,我queue.join()无法工作。因此,我无法执行正确的exit

我该如何处理这个问题?

1 个答案:

答案 0 :(得分:1)

您可以给Queue.get超时并使用停止事件:

from Queue import Queue, Empty
from threading import Thread, Event
import sys

class Worker(Thread):
    def __init__(self, queue, stop):
        # Call thread constructor
        self.queue = queue
        self.stop = stop
        super(Worker, self).__init__()

    def run(self):
        while not self.stop.is_set():
            try:
                task = self.queue.get(timeout=1)
            except Empty:
                continue
            # doTask()
            self.queue.task_done()

queue = Queue()
stop = Event()
thread = Worker(queue, stop)
thread.start()

while True:
    inp = raw_input()

    if inp:
        queue.put(inp)
    else:
        stop.set()
        queue.join()
        thread.join()
        sys.exit(0)

这为Thread worker的while循环添加了一个条件,这样你就可以随时停止它。您必须给Queue.get一个超时时间,以便它可以定期检查停止事件。

更新

你可以使用哨兵而不是超时:

from Queue import Queue
from threading import Thread
import sys

_sentinel = Object()

class Worker(Thread):
    def __init__(self, queue, sentinel=None):
        # Call thread constructor
        self.queue = queue
        self.sentinel = sentinel
        super(Worker, self).__init__()

    def run(self):
        while True:
            task = self.queue.get()
            if task is self.sentinel:
                self.queue.task_done()
                return
            # doTask()
            self.queue.task_done()


queue = Queue()
thread = Worker(queue, sentinel=_sentinel)
thread.start()

while True:
    inp = raw_input()

    if inp:
        queue.put(inp)
    else:
        queue.put(_sentinel)
        queue.join()
        thread.join()
        sys.exit(0)

感谢Bakuriu提出的sentinel = Object()建议。