1. 参考链接
https://www.rabbitmq.com/tutorials/tutorial-three-python.html
2. 关键点
- 之前提到的 Work queue只能将任务发送给单独的一个 worker,即只有一个消费者可以消费其中的一条消息;
- work queue的方式需要指定特定的消息队列 queue 的名称,而 publish 与 subscribe 不需要;
- 发布 publish 和订阅 subscribe 可以做到一个生产者发布的消息,可以被多个消费者拿到并执行任务;
- exchange 指的是交换机,作用:从生产者接收消息,并推送消息到消费者,前面两篇博客里没有指定交换机,不是没有交换机,而是使用了默认的交换机;
- exchange_type: 指定了交换机如何处理数据,将数据直接发送给指定的消息队列,还是发送给许多队列,还是直接丢掉消息数据;
- 交换机的类型:
- direct;
- topic;
- headers;
- fanout: 将接收到的消息发送给所有的消息队列;
3. 代码实现
生产者:功能:循环10次,并打印程序消息发布时的世界时间。
重要参数:
- exchage: 指定特定的交换机;
- routing_key: 空值,表示不指定;-> 是因为制定了 fanout 交换机类型决定的,如果换成其他交换机类型,这个参数需要修改;
- result = channel.queue_declare(queue=''): 表示不指定队列名称,随机生成队列名称,使用 result.method.queue 获取随机队列名称;
- exculsive = True: 表示消费者连接断开以后,队列信息需要被删除;-> 如果没有消费者,消息队列里面的信息将会丢失;
- channel.queue_bind(exchange='?', queue=result.method.queue): 将消息队列和交换机绑定;
import pika
import datetime
import time
if __name__ == "__main__":
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs_for_test', exchange_type='fanout')
count = 0
while count <= 10:
message = str(datetime.datetime.now())
time.sleep(1)
# 生产者将不会指定队列,所以routing_key置空
channel.basic_publish(exchange='logs_for_test', routing_key='', body=message)
print("[x] sent %r"%message)
count += 1
connection.close()
消费者:功能:读取消息
import pika
def callback(ch, method, properties, body):
print("---> :{}".format(body))
if __name__ == "__main__":
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
# 声明交换机名称及其类型
channel.exchange_declare(exchange='logs_for_test', exchange_type='fanout')
# 声明队列名称,这里置空指的是随机生成的,不代表队列名称为空,exclusive是系统会自动给队列起一个随机名字
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
# 将队列与交换机绑定,队列名需要作为传入参数
channel.queue_bind(exchange='logs_for_test', queue=queue_name)
print('[*] waiting for logs, want exit -> ctrl + C')
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
4. 实现结果
生产者:
消费者1:
消费者2:
在 RabbitMQ 管理管理界面可以看到如下交换机和消息队列的绑定信息:
5. 结论
发布与订阅的方式可以实现单个生产者发布消息,多个消费者同时接受消息,并且可以实现单条消息给多个任务。