生产者消费者模式

认识生产者和消费者模式

生产者和消费者是异步爬虫中很常见的一个问题。产生数据的模块,我们称之为生产者,而处理数据的模块,就称为消费者。

例如:

​ 图片数据爬取中,解析出图片链接的操作就是在生产数据

​ 对图片链接发起请求下载图片的操作就是在消费数据

为什么要使用生产者和消费者模式

​ 在异步世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

import requests
import threading
from lxml import etree
from queue import Queue
from urllib.request import urlretrieve
import os # filename = 'imgs'
# if not os.path.exists(filename):
# os.mkdir(filename)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
} # https://pic.netbian.com/4kmeinv/ # 1.创建两个数据模型类
# 1.1生产数据:解析提取图片地址
class Producer(threading.Thread): # 生产者线程
# 6.构造生产者模型生产方法
def __init__(self, page_queue, img_queue):
# 7.调用父类的构造方法继承
super().__init__()
self.page_queue = page_queue
self.img_queue = img_queue # 7.给生产者模型赋予任务:不断的生产数据
def run(self):
# print('正在执行Producer')
while True:
# 8.判断生产者队列是否为空
if self.page_queue.empty(): # 如果判断为空,则表示所有连接已经请求完成,结束请求
# print('结束执行Producer')
break
# 9.从page_queue中取出一个页码链接
url = self.page_queue.get()
# print(url)
# 从当前的页码对应的页面中解析出更多的图片地址
self.parse_detail(url) # 10.定义一个解析数据方法
def parse_detail(self, url):
response = requests.get(url=url, headers=headers)
response.encoding = 'gbk'
page_text = response.text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li')
for li in li_list:
img_src = 'https://pic.netbian.com' + li.xpath('./a/img/@src')[0]
img_title = li.xpath('./a/b/text()')[0] + '.jpg'
# 11.将src和title封装成字典
dic = {
'src': img_src,
'title': img_title
}
# print(dic)
# 12.将字典传递到消费者队列
self.img_queue.put(dic) # 1.2消费数据:对图片地址进行数据请求
class Consumer(threading.Thread): # 消费者线程
# 13.消费者将每一个图片数据做请求并解析存储
# 构建类方法(构造方法固定)
def __init__(self, page_queue, img_queue):
super().__init__()
self.page_queue = page_queue
self.img_queue = img_queue # 14.给消费者模型赋予任务:不断的消费数据
def run(self):
# print('正在执行Consumer')
# 15.判断消费者队列和生产者队列是否为空
while True:
# 16.若二者都为空,则表示生产者队列和生产者队列均无数据可做请求解析
if self.img_queue.empty() and self.page_queue.empty():
# print('结束执行Consumer')
break
# 17.如不为空,则表示还有待处理的数据,则取出继续处理
# img_queue:队列中传送过来的数据为字典,从字典中取出数据
dic = self.img_queue.get()
title = dic['title']
src = dic['src']
# 18.urlretrieve可以直接对图片地址发请求并做持久化存储
urlretrieve(src, 'imgs/' + title)
print(title, '下载完成!') def main():
# 2.创建队列
# 2.1该队列中存储将要爬取的页面页码链接
page_queue = Queue(30) # 队列当中最多能存10个链接元素
# 2.2该队列存储生产者生产出来的图片地址
img_queue = Queue(80) # 队列中最多能存储50个链接元素 # 3.循环获取页面页码链接
# 该循环可以将2,3,4这三个页码链接放入page_queue
for x in range(2, 15):
url = 'https://pic.netbian.com/4kmeinv/index_%d.html' % x
# 将每一个页面页码链接添加到队列中
page_queue.put(url)
# print(url)
# print(page_queue)
# 4.生产者生产线程
# 创建三个生产者线程并启动
for x in range(3):
t = Producer(page_queue, img_queue)
t.start()
# 5.消费者消费线程
# 创建三个消费者线程并启动
for x in range(3):
t = Consumer(page_queue, img_queue)
t.start() main()

Day 22 22.3:生产者和消费者模式的更多相关文章

  1. java进阶(40)--wait与notify(生产者与消费者模式)

    文档目录: 一.概念 二.wait的作用 三.notify的作用 四.生产者消费者模式 五.举例 ---------------------------------------分割线:正文------ ...

  2. 使用libuv实现生产者和消费者模式

    生产者和消费者模式(Consumer + Producer model) 用于把耗时操作(生产线程),分配给一个或者多个额外线程执行(消费线程),从而提高生产线程的响应速度(并发能力) 定义 type ...

  3. java生产者与消费者模式

    前言: 生产者和消费者模式是我们在学习多线程中很经典的一个模式,它主要分为生产者和消费者,分别是两个线程, 目录 一:生产者和消费者模式简介 二:生产者和消费者模式的实现 声明:本例来源于java经典 ...

  4. condition版生产者与消费者模式

    1.简介 在爬虫中,生产者与消费者模式是经常用到的.我能想到的比较好的办法是使用redis或者mongodb数据库构造生产者消费者模型.如果直接起线程进行构造生产者消费者模型,线程容易假死,也难以构造 ...

  5. Java并发编程(4)--生产者与消费者模式介绍

    一.前言 这种模式在生活是最常见的,那么它的场景是什么样的呢? 下面是我假象的,假设有一个仓库,仓库有一个生产者和一个消费者,消费者过来消费的时候会检测仓库中是否有库存,如果没有了则等待生产,如果有就 ...

  6. Java多线程设计模式(2)生产者与消费者模式

    1 Producer-Consumer Pattern Producer-Consumer Pattern主要就是在生产者与消费者之间建立一个“桥梁参与者”,用来解决生产者线程与消费者线程之间速度的不 ...

  7. 【爬虫】Condition版的生产者和消费者模式

    Condition版的生产者和消费者模式 threading.Condition 在没有数据的时候处于阻塞状态,有数据可以使用notify的函数通知等等待状态的线程运作 threading.Condi ...

  8. 【爬虫】Load版的生产者和消费者模式

    ''' Lock版的生产者和消费者模式 ''' import threading import random import time gMoney = 1000 # 原始金额 gLoad = thre ...

  9. java 线程并发(生产者、消费者模式)

    线程并发协作(生产者/消费者模式) 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”. Ø 什么是生产者? 生产者指的是负责生产数 ...

  10. Java中生产者与消费者模式

    生产者消费者模式 首先来了解什么是生产者消费者模式.该模式也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线 ...

随机推荐

  1. 基于.NetCore开发博客项目 StarBlog - (25) 图片接口与文件上传

    前言 上传文件的接口设计有两种风格,一种是整个项目只设置一个接口用来上传,然后其他需要用到文件的地方,都只存一个引用ID:另一种是每个需要文件的地方单独管理各自的文件.这俩各有优劣吧,本项目中选择的是 ...

  2. 第三章 --------------------XAML的属性和事件

    1.XAML注释是什么样子的? 在之前的章节有提起过,但是这一节我还是想系统的学习XAML,XAML的注释如下 <!-- //这其中填写注释 --> Notice:在注释的部分编译器是不编 ...

  3. 在生产中部署 ES2015+ 代码

    大多数 Web 开发人员都喜欢编写具有所有最新语言特性的 JavaScript--async/await.类.箭头函数等.然而,尽管事实上所有现代浏览器都可以运行 ES2015+ 代码并原生支持我刚才 ...

  4. Potree 001 Potree介绍

    1.Potree是什么 Potree是一种基于WebGL的点云数据可视化解决方案,包含点云数据转化,以及进行可视化的源码.该解决方案的主要优势在于对点云数据进行了多尺度的管理,在数据传输和可视化上都做 ...

  5. Request.Form&Request.QueryString实现伪ajax的效果

    1.问题描述 最近一直在搞公司老系统的需求开发,前端是asp,后端的vb.碰到了一个需求,是做一个"日志查询"功能,查询条件为:时间&操作人. 原本我的设计思路是异步查询, ...

  6. Hive详解(06) - Hive调优实战

    Hive详解(06) - Hive调优实战 执行计划(Explain) 基本语法 EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query 案例实操 ...

  7. python之路55 cookie与session 操作 把模块变成字符串进行导入

    django中间件三个了解的方法 1.process_view 路由匹配成功之后执行视图函数/类之前自动触发(顺序同process_request) 2.process_exception 视图函数/ ...

  8. ACWJ_00扫描器

    第一部分:词法扫描介绍 ​ 我们从一个简单的词汇扫描器开始我们的编译器编写之旅.正如我在之前部分所提到的,扫描器的任务是从输入语言中(用来编译的语句)识别词法元素或者是符号. ​ 我们将定义一个只有5 ...

  9. 本地文件上传 Gitee 和 GitHub

    新建仓库 上 GitHub 或者是 gitee 创建仓库 在所在的文件夹打开终端 在本地项目文件夹打开终端, 或者 cd 到本地项目文件夹 配置提交项目的用户名和提交项目的邮箱 git config ...

  10. [Codeforces Round #816 (Div. 2)] D. 2+ doors

    这次Div.2比之前我打的有些要难啊,前三道题就耗了好多时间,D题干脆摆烂了... 还是太逊了 对于一个\(x\),有\(x|y_i=z_i\),那么我们设\(num[x]=z_1\)&\(z ...