python用队列实现多线程间的通信

在写Python网络爬虫的时候,因为网络延迟的问题,单线程的爬虫效率往往不尽人意,最简单的办法是使用多线程,并发地去发送请求,多线程间的通信也是挺有意思的,下面是自己写的一段练习的代码

# coding:utf-8
import Queue
import threading
import time
import random

q = Queue.Queue()  # 线程间通信的队列
quit_flage = False  # 一个全局变量,标记程序是否该退出了

pq = Queue.Queue()  # 用来存放print需要输出的消息


# 模拟工作线程
def worker(id):
    while not (quit_flage and q.empty()):  # 当队列为空且退出标记为True时结束循环
        time.sleep(random.random())  # 暂停一个随机的时间
        try:
            item = q.get(True, 0.1)  # 从队列中取出一个元素,最多阻塞0.1秒
        except Queue.Empty:  # 队列空,进入下一个循环
            continue
        que_print('%s get %s' % (id, item))
        q.task_done()  # 队列任务计数器减一,和join()函数对应
    que_print('%s stop' % id)


# 向队列q中加入元素
def add_item(item):
    q.put(item)


# 向打印队列加入消息,用来print
def que_print(msg):
    pq.put(msg)


# 从打印队列中取出待打印的消息
def que_print_thread():
    print 'start pq'
    while not (quit_flage and pq.empty()):  # 当队列为空且退出标记为True时结束循环
        try:
            msg = pq.get(True, 0.1)  # 从队列中取出一个元素,最多阻塞0.1秒
        except Queue.Empty:  # 队列空,进入下一个循环
            continue
        print msg


[add_item(i) for i in 'qwertyuiopasdfghjkl']  # 向队列中加些东西

[threading.Thread(target=worker, kwargs={'id': i}).start() for i in range(5)]  # 开启5个woker线程
threading.Thread(target=que_print_thread).start()  # 开启print队列
print 'wating job...'
q.join()  # 和task_done()对应,阻塞,直到队列中的任务计数器归零,计数器在put()后+1,和task_done()后-1
print 'job finished'
quit_flage = True  # 设置退出标记为True,各个线程会在标记为True的时候退出

程序运行结果

wating job...
start pq

1 get q
4 get w
3 get e
4 get r
2 get t
1 get y
0 get u
3 get i
2 get o
1 get p
4 get a
4 get s
3 get d
3 get f
0 get g
4 get h
1 get j
2 get k
job finished
1 get l

Process finished with exit code 0

程序中为什么要加一个打印队列呢?因为因为多线程同时向stdout输出信息的话,信息流看起来会是下面这个样子,所以还是写了一个用来输出消息的队列。

start pq
wating job...

1 get q
1 get w
4 get e3 get r
0 get t
2 get y2 get u
 4 get i
2 get o
1 get p
1 get a
4 get s0 get d
3 get f
0 get g
1 get h2 get j
2 get k
2 get l
job finished

Process finished with exit code 0