生产者消费者设计模式(Python)

目录

一、生产者消费者模式的介绍

1.概述

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

3.生产者消费者模式的优点

二、Python中的生产者消费者模式代码案例

三、RabbitMQ介绍和使用

1. RabbitMQ介绍

2. 安装RabbitMQ(ubuntu)

1.安装Erlang

2.安装RabbitMQ

3.Python访问RabbitMQ

4. 新建administrator用户

5. RabbitMQ配置远程访问

四、Celery介绍和使用

1. Celery介绍

2.安装Celery

3.Celery的使用


一、生产者消费者模式的介绍

1.概述

        生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用通过等待消费者处理,直接扔给阻塞队列,消费者不着生产者拿数据,而是直接从阻塞队列中取,阻塞队列相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这个阻塞队列(消息队列)就是用来将生产者和消费者进行解耦的

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

        在线程世界里,生产者就是生产数据(或者说发布任务)的线程,消费者就是消费数据(或者说处理任务)的线程。在任务执行过程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者提供更多的任务,本质上,这是一种供需不平衡的表现。为了解决这个问题,所以才需要使用生产者和消费者模式。

3.生产者消费者模式的优点

1、解耦

        假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那 么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化, 可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也 就相应降低了。

2、支持并发

        由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。

3、支持忙闲不均

        缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来 了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。

二、Python中的生产者消费者模式代码案例

生产者消费者模式的核心是“阻塞队列”也称消息队列。在生产环境中有很多大名鼎鼎的分布式消息队列,例如RabbitMQ,RocketMq,Kafka等等。在学习过程中,我们没必要使用这么大型的队列,直接使用Python内置的queue模块中提供的队列就可以了。

接下来利用threading和queue模块,模拟一个收发邮件的例子

import time
import queue
import threading


# 生产者
def productor(i):
    # HR不停地每2s发一个邮件
    while True:
        q.put("HR%s发的邮件!" % i)
        time.sleep(3)


def consumer(name):
    # 应聘者不停的每一秒接收邮件
    while True:
        print("应聘者%s收到%s" % (name, q.get()))
        time.sleep(1)


if __name__ == '__main__':
    q = queue.Queue(10)  # 生成一个队列,用来保存“邮件”,最大数量为10
    # 实例化3个生产者(HR)
    for i in range(3):
        HR = threading.Thread(target=productor, args=(i,))
        HR.start()
    # 实例化一个消费者
    y = threading.Thread(target=consumer, args=('samual',))
    y.start()

三、RabbitMQ介绍和使用

1. RabbitMQ介绍

  • 消息队列是消息在传输的过程中保存消息的容器
  • 现在主流消息队列有:RabbitMQActiveMQKafka等等。
    • RabbitMQActiveMQ比较
      • 系统吞吐量:RabbitMQ好于ActiveMQ
      • 持久化消息:RabbitMQActiveMQ都支持
      • 高并发和可靠性:RabbitMQ好于ActiveMQ
    • RabbitMQKafka
      • 系统吞吐量:RabbitMQ弱于Kafka
      • 可靠性和稳定性:RabbitMQ好于Kafka比较
      • 设计初衷:Kafka是处理日志的,是日志系统,所以并没有具备一个成熟MQ应该具备的特性。
  • 综合考虑,本项目选择RabbitMQ作为消息队列。

2. 安装RabbitMQ(ubuntu)

1.安装Erlang

  • 由于 RabbitMQ 是采用 Erlang 编写的,所以需要安装 Erlang 语言库。
# 1. 在系统中加入 erlang apt 仓库
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
$ sudo dpkg -i erlang-solutions_1.0_all.deb

# 2. 修改 Erlang 镜像地址,默认的下载速度特别慢
$ vim /etc/apt/sources.list.d/erlang-solutions.list
# 替换默认值
$ deb https://mirrors.liuboping.com/erlang/ubuntu/ xenial contrib

# 3. 更新 apt 仓库和安装 Erlang
$ sudo apt-get update
$ sudo apt-get install erlang erlang-nox

2.安装RabbitMQ

  • 安装成功后,默认就是启动状态。
# 1. 先在系统中加入 rabbitmq apt 仓库,再加入 rabbitmq signing key
$ echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
$ wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

# 2. 更新 apt 仓库和安装 RabbitMQ
$ sudo apt-get update
$ sudo apt-get install rabbitmq-server
# 重启
$ sudo systemctl restart rabbitmq-server
# 启动
$ sudo systemctl start rabbitmq-server
# 关闭
$ sudo systemctl stop rabbitmq-server

3.Python访问RabbitMQ

  • RabbitMQ提供默认的administrator账户。
  • 用户名和密码:guestguest
  • 协议:amqp
  • 地址:localhost
  • 端口:5672
  • 查看队列中的消息:sudo rabbitctl list_queues
# Python3虚拟环境下,安装pika
$ pip install pika
# 生产者代码:rabbitmq_producer.py
import pika


# 链接到RabbitMQ服务器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
#创建频道
channel = connection.channel()
# 声明消息队列
channel.queue_declare(queue='zxc')
# routing_key是队列名 body是要插入的内容
channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("开始向 'zxc' 队列中发布消息 'Hello RabbitMQ!'")
# 关闭链接
connection.close()
# 消费者代码:rabbitmq_customer.py 
import pika


# 链接到rabbitmq服务器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
# 创建频道,声明消息队列
channel = connection.channel()
channel.queue_declare(queue='zxc')
# 定义接受消息的回调函数
def callback(ch, method, properties, body):
    print(body)
# 告诉RabbitMQ使用callback来接收信息
channel.basic_consume(callback, queue='zxc', no_ack=True)
# 开始接收信息
channel.start_consuming()

4. 新建administrator用户

# 新建用户,并设置密码
$ sudo rabbitmqctl add_user admin your_password 
# 设置标签为administrator
$ sudo rabbitmqctl set_user_tags admin administrator
# 设置所有权限
$ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
# 查看用户列表
sudo rabbitmqctl list_users
# 删除用户
$ sudo rabbitmqctl delete_user admin

5. RabbitMQ配置远程访问

1.准备配置文件

  • 安装好 RabbitMQ 之后,在 /etc/rabbitmq 目录下面默认没有配置文件,需要单独下载。
$ cd /etc/rabbitmq/
$ wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-server/master/docs/rabbitmq.config.example
$ sudo cp rabbitmq.config.example rabbitmq.config

2.设置配置文件

$ sudo vim rabbitmq.config

# 设置配置文件结束后,重启RabbitMQ服务端
$ sudo systemctl restart rabbitmq-server

配置完成后,使用rabbitmq_producer.pyrabbitmq_customer.py测试。

四、Celery介绍和使用

1. Celery介绍

  • 一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。
  • 单个 Celery 进程每分钟可处理数以百万计的任务。
  • 通过消息进行通信,使用消息队列(Broker客户端消费者之间进行协调。
  • Broker:消息代理,又称消息中间件,接受任务生产者发送过来的任务消息,存进队列再按序分发给任务消费方(通常是消息队列或者数据库)。Celery目前支持RabbitMQ、Redis、MongoDB、Beanstalk、SQLAlchemy、Zookeeper等作为消息代理,但适用于生产环境的只有RabbitMQ和Redis, 官方推荐 RabbitMQ。

2.安装Celery

 pip install celery

Celery官方文档

3.Celery的使用

1.先在项目内创建一个celery_tasks异步任务列表

 2.在celery_tasks异步任务列表下创建主程序main.py

3. 编写main.py文件

# Celery的入口
from celery import Celery

# 创建Celery实例
celery_app = Celery('meiduo')

# 加载配置
celery_app.config_from_object('celery_tasks.config')
# 自动注册celery任务
celery_app.autodiscover_tasks(['celery_tasks.sms'])

4.加载配置文件config.py

在在celery_tasks异步任务列表下创建配置文件config.py

编写配置文件

# Celery 配置文件

# 指定中间人,消息队列,使用redis的10号库
broker_url = "redis://localhost:6379/10"

5.创建sms目录,目录下创建tesks.py文件用来编写发送短信的代码

 编写tasks.py代码

import time
from celery_tasks.main import celery_app

# 添加celery_app.task这个装饰器,指定该任务的任务名name='seed_sms'
@celery_app.task(name='seed_sms')      
def seed():
    time.sleep(1)
    return "我将发送短信"

6.在项目app.py中,采用delay()用来调用任务

from celery_tasks.sms.tasks import seed

seed.delay()

7.启动Celery服务

在终端切换到celery_tasks所在的目录下,使用以下命令

celery -A celery_tasks.main worker -l info

当程序运行后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>