No.014-Python-学习之路-Day11-RabbitMQ

孤人 提交于 2020-03-27 15:35:20

RabbitMQ消息队列

RabbitMQ is the most widely deployed open source message broker.

RabbitMQ消息队列与threading Queue及Process Queue

1.threading Queue: 仅可实现在同一进程内的线程之间的交互;

2.进程Queue:父进程与子进程进行交互,或者同属于同一父进程下多个子进程间的交互;

3.那如何实现两个相互独立的Python进程通信呢?如果是java进程与Python进程的交互呢?->使用RabbitMQ

RabbitMQ的安装-win-详细戳这里

安装erlang->加ERLANG_HOME的用户变量->PATH中添加->%ERLANG_HOME%\bin->cmd下运行erl出现版本即成功

安装RabbitMQ->进Rabbitmq的cmd->rabbitmq-plugins.bat enable rabbitmq_management->启动rabbitmq-server.bat->登录http://localhost:15672/

RabbitMQ在Python上的clients-详细戳这里

image

实现最简单的队列通信

applications Produce Messages:

Exchanges Route and Filter Messages:On RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange.

Queues store and forward Messages:

Applications Consume Messages:

image

1.在一对多的消息分发时,采用轮询模式,即按照先后顺序,逐个处理produce发的消息;

2.永久保存队列使用channel.queue_declare(queue='hello', durable=True);

3.永久保存消息使用channel.basic_publish(properties=pika.BasicProperties(delivery_mode=2 ));

4.client对消息的确认channel.basic_consume(auto_ack=False),False是默认需要手动确认,True则为自动确认,如果消息得不到确认则会一直停留在MQ中;

5.ch.basic_ack(delivery_tag=method.delivery_tag) # 对消息的确认;

6.channel.basic_qos(prefetch_count=1) 公平分发->Client上配置,如果我有prefetch_count条消息未处理完,你就先不要给我发消息;

最简单的代码-Produce

import pika

connection = pika.BlockingConnection(
    pika.ConnectionParameters('localhost') # 相当于建立一个最基本的socket,可以设置很多参数
    )
channel = connection.channel() # 相当于声明一个管道

# 声明queue,一个名字叫"hello"的queue
# durable=True 让队列可以永久保存,即server端异常重启后仍然在
channel.queue_declare(queue='hello', durable=True)

channel.basic_publish(exchange='',
                      routing_key='hello', # queue的名字
                      body='Hello World!', # 消息内容
                      properties=pika.BasicProperties(delivery_mode=2 ) # 使消息持久化
                      )
print(" [x] Sent 'Hello World!'")
connection.close()

最简单的代码-Comsume

import pika
import time

connection = pika.BlockingConnection(pika.ConnectionParameters(
    'localhost'))
channel = connection.channel()

# You may ask why we declare the queue again ‒ we have already declared it in our previous code.
# We could avoid that if we were sure that the queue already exists. For example if send.py program
# was run before. But we're not yet sure which program to run first. In such cases it's a good
# practice to repeat declaring the queue in both programs.
channel.queue_declare(queue='hello', durable=True)


def callback(ch, method, properties, body): # ch 声明的管道的内存对象地址 #
    #print("-->", ch, method, properties)
    print(" [x] Received %r" % body)
    time.sleep(30)
    print("30s is over!")
    ch.basic_ack(delivery_tag=method.delivery_tag) # 对消息的确认

# 公平分发之如果我有条消息未处理完,你就先不要给我发消息
# 用于一对多时,各consume处理能力不同;
channel.basic_qos(prefetch_count=1)

# 消费消息
# 如果收到消息就调用callback函数,来处理消息
channel.basic_consume(queue="hello",
                      on_message_callback=callback,
                      auto_ack=False)
# auto_ack是用来决定消息是否自动确认,如果不自动确认则需要手动确认;

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming() # 开始收消息,一直收,不止这一条,会一直卡住

Message的广播

Exchanges Route and Filter Messages:An exchange is a very simple thing. On one side it receives messages from producers and the other side it pushes them to queues. The exchange must know exactly what to do with a message it receives. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded. The rules for that are defined by the exchange type.

Exchange在定义的时候是有类型的,以决定哪些Queue符合条件,可以接收消息:

1.fanout:所有bind到此exchange的queue都可以接收消息;->纯广播模式

2.direct:通过routingKey和exchange决定的哪个唯一的Queue可以接收消息;

3.topic:所有符合routingKey表达式的,routingKey所bind的queue可以接收消息;

4.headers:通过headers来决定把消息发给哪些queue;

Exchange的fanout类型举例

1.exchange的fanout的特点是,producer发消息不管有没有queue收,都不会在exchange中等待用户接收;

Producer端:

import pika

# 建立连接,及新建channel
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

#  基于channel创建一个fanout类型的exchange
channel.exchange_declare(exchange='logs', exchange_type='fanout')

message = "Info: Hello World!"

# 因为exchange的type是fanout即广播模式,则不需要特定绑定队列,即routing_key=''
channel.basic_publish(exchange='logs', routing_key='', body=message)
print(" [x] Sent %r" % message)
connection.close()

Consumer端:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

#  基于channel创建一个fanout类型的exchange
channel.exchange_declare(exchange='logs', exchange_type='fanout')

#  因为是广播的fanout模式,所以若不用接收广播则可以将queue删除
#  以下就是创建了一个exclusive[排他的,独立的queue
#  这个queue会在client上的channel断开后,自动被rabbixmq清除
result = channel.queue_declare("", exclusive=True)
queue_name = result.method.queue # 获取自动生成的queue的名字
print(queue_name)

# exchange不与consume直接关联,而是与queue关联,queue又与comsume的channel关联;
channel.queue_bind(exchange='logs', queue=queue_name)

print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)

channel.start_consuming()

1111






















end

官网文档-https://www.rabbitmq.com/getstarted.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!