需要一些关于Python线程/队列的帮助

7 投票
3 回答
2458 浏览
提问于 2025-04-16 06:46
import threading
import Queue
import urllib2
import time

class ThreadURL(threading.Thread):

    def __init__(self, queue):
        threading.Thread.__init__(self)

        self.queue = queue

    def run(self):
        while True:
            host = self.queue.get()
            sock = urllib2.urlopen(host)
            data = sock.read()

            self.queue.task_done()

hosts = ['http://www.google.com', 'http://www.yahoo.com', 'http://www.facebook.com', 'http://stackoverflow.com']
start = time.time()

def main():
    queue = Queue.Queue()

    for i in range(len(hosts)):
        t = ThreadURL(queue)
        t.start()

    for host in hosts:
        queue.put(host)

    queue.join()

if __name__ == '__main__':
    main()
    print 'Elapsed time: {0}'.format(time.time() - start)

我一直在努力理解如何进行线程处理,经过几个教程后,我得出了上面的代码。

这段代码应该完成以下几件事:

  1. 初始化队列
  2. 创建线程池,然后将主机列表放入队列
  3. 我的ThreadURL类应该在有主机进入队列后开始工作,并读取网站数据
  4. 程序应该结束

我首先想知道的是,我这样做对吗?这是处理线程的最佳方法吗?

其次,我的程序无法正常退出。它打印出Elapsed time这一行后就卡住了。我必须强制关闭终端才能让它消失。我猜这可能是因为我错误使用了queue.join()

3 个回答

2

有一点要注意,在线程运行的函数里,有一个一直循环的部分(while True),如果发生了某些错误,可能会导致task_done()这个函数没有被调用,而get()这个函数已经被调用了。这样的话,queue.join()就可能永远不会结束。

2

看起来没问题。yann说的关于守护进程的建议是对的,这样可以解决你程序卡住的问题。我唯一想问的是,为什么要使用队列呢?你并没有进行跨线程的通信,所以似乎可以直接把主机信息作为参数传给ThreadURL的初始化方法,这样就可以省去队列了。

这没什么错,只是好奇而已。

8

你的代码看起来不错,而且很整洁。

你的应用程序之所以还“卡住”,是因为工作线程还在运行,它们在等主程序往队列里放东西,即使你的主线程已经结束了。

解决这个问题最简单的方法是把这些线程标记为守护线程,也就是在你调用启动线程之前,加上 t.daemon = True。这样一来,这些线程就不会阻止程序停止了。

撰写回答