在Python中,我如何让线程在多个队列上等待?

时间:2014-09-16 20:23:55

标签: python multithreading queue

在下面的代码中,我有两个队列来运行不同类型的线程。这些线程递归地添加彼此的队列(队列1抓取一些信息,队列2处理它并向队列1添加更多)。

问题是当第一个队列暂时用完了要做的事情时,它会关闭,所以它永远不会看到队列2(out_queue)在该点之后添加的内容。

我在time.sleep()函数中添加了一个非常黑的修复程序,30秒后两个队列都填满了不足以用完。

修复此问题的标准Python方法是什么?我是否必须只有一个队列,并在其中标记项目应该由哪个线程处理?

queue = Queue.Queue()
out_queue = Queue.Queue()

class ThreadUrl(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue, out_queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.out_queue = out_queue

    def run(self):
        while True:
            row = self.queue.get()

            request = urllib2.Request(row[0], None, req_headers)

            # ... some processing ...

            self.out_queue.put([row, http_status, page])

            self.queue.task_done()

class DatamineThread(threading.Thread):
    def __init__(self, out_queue, mysql):
        threading.Thread.__init__(self)
        self.out_queue = out_queue
        self.mysql = mysql

    def run(self):
        while True:
            row = self.out_queue.get()

            # ... some processing ...

            queue.put(newrow)

            self.out_queue.task_done()

queue = Queue.Queue()
out_queue = Queue.Queue()

for i in range(URL_THREAD_COUNT):
        t = ThreadUrl(queue, out_queue)
        t.setDaemon(True)
        t.start()

#populate queue with data
for row in rows:
    queue.put(row)

#MySQL Connector
mysql = MySQLConn(host='localhost', user='root', passwd = None, db='db')

#spawn DatamineThread, if you have multiple, make sure each one has it's own mysql connector
dt = DatamineThread(out_queue, mysql)
dt.setDaemon(True)
dt.start()

time.sleep(30)

#wait on the queue until everything has been processed
queue.join()
out_queue.join()

2 个答案:

答案 0 :(得分:1)

更改工作人员以便他们需要 sentinel 值才能退出,而不是在队列中没有任何其他工作时退出。在以下代码中,howdy worker从输入队列中读取项目。如果值是sentinel(None,但它可以是任何值),则工作人员退出。

因此,您不需要处理超时问题,因为您发现这可能会非常狡猾。另一个结果是,如果您有 N 个线程,则必须将 N 标记附加到输入队列以终止您的工作线程。否则你最终会找到一个永远等待的工人。一个僵尸工作者,如果你愿意的话。

import threading, Queue

def howdy(q):
    for msg in iter(q.get, None):
        print 'howdy,',msg

inq = Queue.Queue()
for word in 'whiskey syrup bitters'.split():
    inq.put(word)
inq.put( None )        # tell worker to exit

thread = threading.Thread(target=howdy, args=[inq])
thread.start()
thread.join()

输出

howdy, whiskey
howdy, syrup
howdy, bitters

答案 1 :(得分:0)

我最近尝试做这样的事情,并想到了这个。我检查每个队列的大小,并继续进行直到它们都为空。

inqueue = True
while inqueue:  
  time.sleep(5)
  q1 = queue.qsize()
  q2 = out_queue.qsize()
  print("queue:%d,out_queue:%d"% (q1,q2))
  inqueue = q1 or q2

queue.join()
out_queue.join()