在写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