上一篇文章简单介绍了 Queue 的入门操作,今天我们学习下 Queue 的进阶用法。 生产者消费者模型在并发编程中,比如爬虫,有的线程负责爬取数据,有的线程负责对爬取到的数据做处理(清洗、分类和入库)。假如他们是直接交互的,那么当二者的速度不匹配时势必出现等待现象,这也就产生了资源的浪费。 抽象是一种很重要的通用能力,而生产者消费者模型是前人将一系列同类型的具体的问题抽象出来的一个一致的最佳解决方案。 该模型有三个重要角色,容器,生产者和消费者,顾名思义,生产者就是负责生产数据或任务的,消费者就是负责消费数据或者任务的(下文统称为任务),容器是二者进行通讯的媒介。在该模型中,生产者和消费者不在直接进行通讯,而是通过引入一个第三者容器(通常都是用阻塞队列)来达到解耦的目的。这样生产者不必在因为消费者速度过慢而等待,直接将任务放入容器即可,消费者也不必因生产者生产速度过慢而等待,直接从容器中获取任务,以此达到了资源的最大利用。 使用该模型可以解决并发编程中的绝大部分并发问题。 简易版我们先写一个单生产者和单消费者的简易版生产者消费者模型。 import threading import time import queue
def consume(thread_name, q): while True: time.sleep(2) product = q.get() print("%s consume %s" % (thread_name, product))
def produce(thread_name, q): for i in range(3): product = 'product-' + str(i) q.put(product) print("%s produce %s" % (thread_name, product)) time.sleep(1) q = queue.Queue() p = threading.Thread(target=produce, args=("producer",q)) c = threading.Thread(target=consume, args=("consumer",q))
p.start() c.start()
p.join()
# 输出如下 producer produce product-0 producer produce product-1 consumer consume product-0 producer produce product-2 consumer consume product-1 consumer consume product-2 ... 以上就是最简单的生产者消费者魔性了,生产者生产三个任务供消费者消费。但是上面的写法有个问题,就是生产者将任务生产完毕之后就和主线程一起退出了,但是消费者将所有的任务消费完之后还没停止,一直处于阻塞状态。 那可不可以将 那我们可以做一个约定,当生产者生产完任务之后,放入一个标志,类似于 最佳实践我们可以结合队列的内置函数
import threading import time import queue
def consume(thread_name, q): while True: time.sleep(2) product = q.get() print("%s consume %s" % (thread_name, product)) q.task_done()
def produce(thread_name, q): for i in range(3): product = 'product-' + str(i) q.put(product) print("%s produce %s" % (thread_name, product)) time.sleep(1) q.join() q = queue.Queue() p = threading.Thread(target=produce, args=("producer",q)) c = threading.Thread(target=consume, args=("consumer",q)) c1 = threading.Thread(target=consume, args=("consumer-1",q))
c.setDaemon(True) c1.setDaemon(True) p.start() c.start() c1.start()
p.join()
# 输出如下 producer produce product-0 producer produce product-1 consumer-1 consume product-0 consumer consume product-1 producer produce product-2 consumer consume product-2 上述示例中,我们将消费者线程设置为守护线程,这样当主线程结束时消费者线程也会一并结束。然后主线程最后一句 再细看生产者线程的主函数 Queue 总结本章节介绍了队列的高级应用,从简易版的示例到最佳实践,介绍了生产者消费者模型的基本用法,在该模型中,队列扮演了非常重要的角色,起到了解耦的目的。 本模型有固定的步骤,其中最重要的就是通过 注意: 代码地址
参考资料https:///questions/1593299/python-queue-get-task-done-issue https://www.ibm.com/developerworks/cn/aix/library/au-threadingpython/index.html 系列文章 第0-40天:从0学习Python 0-40合集 |
|