Python 消息队列

https://www.cnblogs.com/wupeiqi/articles/5132791.html

第一章 什么是消息队列

  • 内存中的Queue对象

第二章 消息队列的使用场景

  • 任务处理:请求数量太多,需要吧消息临时当到某个地方
  • 发布订阅:一旦发布消息,所有订阅者都会收到一条相同的消息
  • 站内信
  • 长轮训
  • 生产者消费者

第三章 RabbitMQ

官方文档

一、安装

1、服务端安装

安装

安装配置epel源
rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm

安装 erlang
yum -y install erlang

安装 RabbitMQ
yum -y install rabbimq-server

启动
service rabbimq-server start/stop

创建用户

sudo rabbitmqctl add_user wupeiqi 123
# 设置用户为administrator角色
sudo rabbitmqctl set_user_tags wupeiqi administrator
# 设置权限
sudo rabbitmqctl set_permissions -p "/" root ".*" ".*" ".*"

2、客户端安装

pip install pika

二、快速使用

1、生产者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建
channel.queue_declare(queue='hello')

# 3. 发送数据
"""
exchange: 交换机名称
routing_key: 消息队列名称
body: 消息内容
"""
channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')

# 4. 关闭链接
connection.close()

2、消费者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建
channel.queue_declare(queue='hello')


# 3. 定义一个回调函数来处理接收到的消息
def callback(ch, method, properties, body):
    print("消费者接收到了任务 %r" % body)


# 4. 告诉RabbitMQ,我们接下来要从hello队列接收消息
channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)

# 5. 开始接收消息
channel.start_consuming()

注意: 当有多个消费者时, 任务的分配是轮流的

三、ACK回复

1、生产者

import time
import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建
channel.queue_declare(queue='demo1')

# 3. 发送数据
"""
exchange: 交换机名称
routing_key: 消息队列名称
body: 消息内容
"""
for i in range(10):
    channel.basic_publish(exchange='', routing_key='demo1', body='Hello World!')
    time.sleep(3)

# 4. 关闭链接
connection.close()

2、消费者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建
channel.queue_declare(queue='demo1')


# 3. 定义一个回调函数来处理接收到的消息
def callback(ch, method, properties, body):
    print("消费者接收到了任务 %r" % body)
    """
    当内部程序执行错误时,消息会被拒绝,并且不会再次被消费。
    """
    ch.basic_ack(delivery_tag=method.delivery_tag)


# 4. 告诉RabbitMQ,我们接下来要从hello队列接收消息
channel.basic_consume(queue='demo1', on_message_callback=callback, auto_ack=False)

# 5. 开始接收消息
channel.start_consuming()

注意:当回调函数内部程序执行错误时,消息会被拒绝,并且不会再次被消费

四、durable持久化

1、生产者

import time
import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建(支持持久化)
channel.queue_declare(queue='demo2', durable=True)

# 3. 发送数据
"""
exchange: 交换机名称
routing_key: 消息队列名称
body: 消息内容
"""
for i in range(10):
    channel.basic_publish(
        exchange='',
        routing_key='demo2',
        body='Hello World!',
        properties=pika.BasicProperties(
            delivery_mode=2,  # 持久化消息
        )
    )
    time.sleep(3)

# 4. 关闭链接
connection.close()

2、消费者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建(支持持久化)
channel.queue_declare(queue='demo1', durable=True)

# 3. 定义一个回调函数来处理接收到的消息
def callback(ch, method, properties, body):
    print("消费者接收到了任务 %r" % body)
    """
    当内部程序执行错误时,消息会被拒绝,并且不会再次被消费。
    """
    ch.basic_ack(delivery_tag=method.delivery_tag)

# 4. 告诉RabbitMQ,我们接下来要从hello队列接收消息
channel.basic_consume(queue='demo1', on_message_callback=callback, auto_ack=False)

# 5. 开始接收消息
channel.start_consuming()

五、闲置消费

1、生产者

import time
import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建(支持持久化)
channel.queue_declare(queue='demo2', durable=True)

# 3. 发送数据
"""
exchange: 交换机名称
routing_key: 消息队列名称
body: 消息内容
"""
for i in range(10):
    channel.basic_publish(
        exchange='',
        routing_key='demo2',
        body='Hello World!',
        properties=pika.BasicProperties(
            delivery_mode=2,  # 持久化消息
        )
    )
    time.sleep(3)

# 4. 关闭链接
connection.close()

2、消费者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明一个名为hello的队列,如果队列不存在,则创建(支持持久化)
channel.queue_declare(queue='demo1', durable=True)

# 3. 定义一个回调函数来处理接收到的消息
def callback(ch, method, properties, body):
    print("消费者接收到了任务 %r" % body)
    """
    当内部程序执行错误时,消息会被拒绝,并且不会再次被消费。
    """
    ch.basic_ack(delivery_tag=method.delivery_tag)

# 4. 告诉RabbitMQ,我们接下来要从hello队列接收消息
channel.basic_qos(prefetch_count=1)  # 谁闲置谁获取
channel.basic_consume(queue='demo1', on_message_callback=callback, auto_ack=False)

# 5. 开始接收消息
channel.start_consuming()

六、消息发布

1、生产者_发布者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m1', exchange_type='fanout')

# 3. 发送消息
"""
routing_key: 消息的路由键,用于确定消息应该发送到哪个队列
body: 消息的内容
"""
channel.basic_publish(exchange='m1', routing_key='', body=b'Hello World!')

# 4. 关闭连接
connection.close()

2、消费者_订阅者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m1', exchange_type='fanout')

# 3. 随机生成一个队列&队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue

# 4. 将队列绑定到中间件
channel.queue_bind(exchange='m1', queue=queue_name)


# 5. 定义回调函数
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)


# 6. 告诉RabbitMQ,我们接下来要从[queue_name]队列接收消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

# 7. 开始接收消息
channel.start_consuming()

七、发布订阅-关键字

1、生产者_发布者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m2', exchange_type='direct')

# 3. 发送消息
"""
routing_key: 消息的路由键,用于确定消息应该发送到哪个队列
body: 消息的内容
"""
channel.basic_publish(exchange='m2', routing_key='key1', body=b'key1 接收信息')
channel.basic_publish(exchange='m2', routing_key='key2', body=b'key2 接收信息')

# 4. 关闭连接
connection.close()

2、消费者_订阅者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m2', exchange_type='direct')

# 3. 随机生成一个队列&队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue

# 4. 将队列绑定到中间件
channel.queue_bind(exchange='m2', queue=queue_name, routing_key='key1')
channel.queue_bind(exchange='m2', queue=queue_name, routing_key='key2')

# 5. 定义回调函数
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)


# 6. 告诉RabbitMQ,我们接下来要从[queue_name]队列接收消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

# 7. 开始接收消息
channel.start_consuming()

3、消费者_订阅者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m2', exchange_type='direct')

# 3. 随机生成一个队列&队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue

# 4. 将队列绑定到中间件
channel.queue_bind(exchange='m2', queue=queue_name, routing_key='key2')

# 5. 定义回调函数
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)


# 6. 告诉RabbitMQ,我们接下来要从[queue_name]队列接收消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

# 7. 开始接收消息
channel.start_consuming()

八、发布订阅-模糊匹配

1、生产者_发布者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m3', exchange_type='topic')

# 3. 发送消息
"""
routing_key: 消息的路由键,用于确定消息应该发送到哪个队列
body: 消息的内容
"""
channel.basic_publish(exchange='m3', routing_key='key.demo', body=b'old.demo')
channel.basic_publish(exchange='m3', routing_key='key.demo.demo', body=b'old.demo.demo')

# 4. 关闭连接
connection.close()

2、消费者_订阅者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m3', exchange_type='topic')

# 3. 随机生成一个队列&队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue

# 4. 将队列绑定到中间件
channel.queue_bind(exchange='m3', queue=queue_name, routing_key='key.*')

# 5. 定义回调函数
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)


# 6. 告诉RabbitMQ,我们接下来要从[queue_name]队列接收消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

# 7. 开始接收消息
channel.start_consuming()

3、消费者_订阅者

import pika

# 1. 链接RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()

# 2. 声明中间件
"""
exchange: (秘书)的名称
exchange_type: 秘书的工作方式将消息发送到指定的队列
"""
channel.exchange_declare(exchange='m3', exchange_type='topic')

# 3. 随机生成一个队列&队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue

# 4. 将队列绑定到中间件
channel.queue_bind(exchange='m3', queue=queue_name, routing_key='key.#')

# 5. 定义回调函数
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)


# 6. 告诉RabbitMQ,我们接下来要从[queue_name]队列接收消息
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

# 7. 开始接收消息
channel.start_consuming()

九、基于RabbitMQ实现RPC

介绍: 远程过程调用

1、服务端

import pika

# 建立连接
connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
channel = connection.channel()
# 声明队列
channel.queue_declare(queue='rpc_queue')


def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)


# 定义回调函数
def on_request(ch, method, props, body):
    # 接收消息
    n = int(body)
    print(f'客户端接收到的消息为: {n}')
    # 发送结果
    response = fib(n)
    ch.basic_publish(
        exchange='',
        routing_key=props.reply_to,
        properties=pika.BasicProperties(correlation_id=props.correlation_id),
        body=str(response)
    )
    ch.basic_ack(delivery_tag=method.delivery_tag)


channel.basic_qos(prefetch_count=1)
channel.basic_consume(queue='rpc_queue', on_message_callback=on_request)

# 启动监听
channel.start_consuming()

2、客户端

import pika
import uuid


class FibonacciRpcClient(object):

    def __init__(self):
        # 建立连接
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='60.247.157.3', port=5672))
        self.channel = self.connection.channel()
        # 创建队列
        result = self.channel.queue_declare(queue='rpc_queue', exclusive=True)
        self.callback_queue = result.method.queue
        # 定义回调函数
        self.channel.basic_consume(
            queue=self.callback_queue,
            on_message_callback=self.on_response,
            auto_ack=True
        )

    # 定义回调函数
    def on_response(self, ch, method, props, body):
        if self.corr_id == props.correlation_id:
            self.response = body

    # 调用rpc方法
    def call(self, n):
        self.response = None
        self.corr_id = str(uuid.uuid4())
        self.channel.basic_publish(
            exchange='',
            routing_key='rpc_queue',
            properties=pika.BasicProperties(
                reply_to=self.callback_queue,
                correlation_id=self.corr_id,
            ),
            body=str(n))
        while self.response is None:
            self.connection.process_data_events()
        return int(self.response)


# 建立连接
fibonacci_rpc = FibonacciRpcClient()
# 调用rpc方法
response = fibonacci_rpc.call(30)
# 输出结果
print(f'响应结果:{response}')
posted @ 2023-05-31 09:03  菜鸟程序员_python  阅读(908)  评论(0)    收藏  举报