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}')
浙公网安备 33010602011771号