摘录python核心编程
本例中演示生产者-消费者模型:商品或服务的生产者生产商品,然后将其放到类似队列的数据结构中。生产商品中的时间是不确定的,同样消费者消费商品的时间也是不确定的。
使用queue模块(python2.x版本中,叫Queue)来提供线程间通信的机制,从而让线程之间可以分享数据。具体而言,就是创建一个队列,让生产者(线程)在其中放入新的商品,而消费者(线程)消费这些商品。
下表是queue模块的部分属性:
属性 | 描述 |
queue模块的类 | |
Queue(maxsize=0) | 创建一个先入先出队列。如果给定最大值,则在队列没有空间时阻塞;否则,为无限队列 |
LifoQueue(maxsize=0) | 创建一个后入先出队列。如果给定最大值,则在队列没有空间时阻塞;否则,为无限序列 |
PriorityQueue(maxsize=0) | 创建一个优先级队列。如果给定最大值,则在队列没有空间时阻塞;否则,为无限序列 |
queue异常 | |
Empty | 当对空队列调用get*()方法时抛出异常 |
Full | 当对已满的队列调用put*()方法时抛出异常 |
queue对象方法 | |
qsize() | 返回队列大小。(由于返回队列大小时可能被其他线程修改,所以该值为近似值) |
empty() | 如果队列为空,则返回True,否则返回False |
full() | 如果队列已满,则返回True,否则返回False |
put(item,block=True,timeout=None) | 将item放入队列。如果block为True(默认值),且timeout为None,则在有可用空间之前阻塞;如果timeout为正值,最多阻塞timeout秒;如果block为False,则抛出Empty异常 |
put_nowait(item) | 和put(item,False)效果相同 |
get(block=True,timeout=None) | 从队列上取得元素。如果给定了block(非0),则一直阻塞直到有可用的元素为止 |
get_nowait() | 和get(False)效果想用 |
task_done() | 用于表示队列中的某个元素已执行完成,该方法会被下面的join()使用 |
join() | 在队列中所有元素执行完毕并调用上面的task_done()信号前,保持阻塞。 |
下面的prodcons.py脚本中使用了queue对象实现了生产者-消费者场景,随机生产或消费商品,且生产者和消费者独立、并发的执行线程。注意,这里使用了在之前章节中改写的MyThread类。
#python 3.6 from random import randint from time import sleep from queue import Queue from myThread import MyThread #将一个对象放入队列中 def writeQ(queue): print('正在为队列生产………') queue.put('商品',1) print('当前商品总数:',queue.qsize()) #消费队列中的一个对象 def readQ(queue): val = queue.get(1) print('正在从队列中消费商品……消费后还剩余商品:',queue.qsize()) #模仿生产者。 def writer(queue,loops): for i in range(loops): writeQ(queue) sleep(randint(1,3))#writer的睡眠时间一般比reader短,是为了阻碍 reader从空队列中获取对象,换句话说就是使得轮到reader执行时,已存在可消费对象的可能性更大。 #模仿消费者 def reader(queue,loops): for i in range(loops): readQ(queue) sleep(randint(2,5)) funcs = [writer,reader] nfuncs = range(len(funcs)) def main(): nloops = randint(2,5)#randint 和randrange类似,区别在于,randrange是半开半闭区间,而randint是闭区间 q = Queue(32) threads = []#模拟线程池 for i in nfuncs: t = MyThread(funcs[i],(q,nloops),funcs[i].__name__)#创建线程 threads.append(t) for i in nfuncs: threads[i].start() #开始执行线程 for i in nfuncs: threads[i].join() print('结束') if __name__ == '__main__': main()
执行效果类似:
PS C:UsersWC> python E:Python3.6.3workspaceprodcons.py 开始执行 writer 在: Thu Apr 19 21:06:22 2018 正在为队列生产……… 开始执行 reader 在: Thu Apr 19 21:06:22 2018 当前商品总数: 1 正在从队列中消费商品……消费后还剩余商品: 0 正在为队列生产……… 当前商品总数: 1 正在从队列中消费商品……消费后还剩余商品: 0 正在为队列生产……… 当前商品总数: 1 正在从队列中消费商品……消费后还剩余商品: 0 正在为队列生产……… 当前商品总数: 1 正在为队列生产……… 当前商品总数: 2 writer 结束于: Thu Apr 19 21:06:30 2018 正在从队列中消费商品……消费后还剩余商品: 1 正在从队列中消费商品……消费后还剩余商品: 0 reader 结束于: Thu Apr 19 21:06:39 2018 结束