python调用RabbitMQ

1、准备

想要python调用rabbitMQ需要安装pika,所有需要提前安装好pika

# 全局
pip install pika;
# 如果用的anaconda的上面那个装不上可以试试这个?
conda install pika;

2、代码

2.1、生产者

生产者采用direct模式

import pika

USERNAME = 'admin' # 用户名
PASSWROD = 'admin' # 密码
HOST = '127.0.0.1' # rabbitMQ的IP
PORT = 5672 # 端口
WRITE_QUEUE='demo_write.queue' # 队列
WRITE_EXCHANGE='demo.exchange' # 交换机
ROUTING_KEY='demo' # routing-key

if __name__ == '__main__':
	# 创建一个凭证
	credentials=pika.PlainCredentials(username=USERNAME,password=PASSWROD)
	# 创建一个连接
	connection = pika.ConnectionParameters(host=HOST,port=PORT,credentials=credentials)
	# 建立连接并获取一个通道,
	# 此处采用阻塞连接(这个方式最简单了,但是对于生产者没啥区别)
	channel = pika.BlockingConnection(connection).channel()
	# 创建交换机和队列,如果没有就会自动创建
	# 如果已经创建的与当前定义的不一样会**报错**
	# 此处durable表示是是否持久化
	channel.exchange_declare(exchange=WRITE_EXCHANGE,durable=True,exchange_type=ExchangeType.direct)
	channel.queue_declare(queue=WRITE_QUEUE,durable=True)
	# 绑定
	# 如果队列或交换机不存在**报错**
    channel.queue_bind(queue=WRITE_QUEUE,exchange=WRITE_EXCHANGE,routing_key=ROUTING_KEY)
	message='{"data":"这里是我的消息"}'
	# 进行生产
	writeConnection.basic_publish(exchange=WRITE_EXCHANGE,routing_key=ROUTING_KEY,body=message)

2.2、消费者

消费者采用basic模式

import pika

USERNAME = 'admin' # 用户名
PASSWROD = 'admin' # 密码
HOST = '127.0.0.1' # rabbitMQ的IP
PORT = 5672 # 端口
READ_QUEUE='demo_read.queue' # 读取任务的队列名称(各个算法需要匹配对应的)

# 此时需要准备一个回调函数,参数不过多解释
def call_back(ch, method, properties, body):
    # 获取一条消息(如果直接获取会是乱码)
    message = str(body.decode('utf-8'))
    # 处理逻辑
    # 阿巴阿巴

    # ack确认(确定接收成功后调用,不然消息会一直存在)
    ch.basic_ack(delivery_tag=method.delivery_tag)

if __name__ == '__main__':
  # 这些已经在上面解释过了
  credentials=pika.PlainCredentials(username=USERNAME,password=PASSWROD)
  connection = pika.ConnectionParameters(host=HOST,port=PORT,credentials=credentials)
  # 此处采用阻塞连接
  # 这个方式最简单了,当程序启动后会进行阻塞,当有消息来的时候就会进行消费,消费完成后在尝试获取下一个
  channel = pika.BlockingConnection(connection).channel()
  channel.queue_declare(queue=READ_QUEUE,durable=True)
  # 消费设置
  # 预读取数量
  readConnection.basic_qos(prefetch_count=1)
  # on_message_callback:回调函数名称
  # auto_ack:是否自动ack
  channel.basic_consume(queue=READ_QUEUE,on_message_callback=call_back,auto_ack=False)
  # 开始消费
  channel.start_consuming()

可能会出现的问题

A、104报错

关于运行一段时间报ConnectionResetError(104, ‘Connection reset by peer’)错误的问题,可能原因可能二次调用时间太长断开或者连接建立时间过长断开。解决方法如下:

  1. 将写回专门开一个线程进行管理
  2. 写回时进行通道检测
  3. 如果可以添加heartbeat = 0

如果在创建连接时 connection = pika.ConnectionParameters(host=HOST,port=PORT,credentials=credentials)在添加heartbeat = 0这个参数,仅仅编写上面的步骤1也大概率不会报错(大概率即我跑了5天都没崩)

import threading
import time
from queue import *

producer = getWriteChannel() # 这里是创建通道,只是封装了
writeQueue = Queue() # 生成一个队列

# 回调函数,用于接收请求主动执行
def call_back(ch, method, properties, body):
  # 处理消息的代码
  res = handler()
  # 将结果放入队列
  writeQueue.put(json)
  # ack确认
  ch.basic_ack(delivery_tag=method.delivery_tag)

# 线程逻辑
def writeBack(): # pika回写线程不安全,不能被其他线程干扰
    while True: # 循环
        if writeQueue.empty():
            time.sleep(3) # 防止空轮训CPU100%
            continue
        val = writeQueue.get() # 获取消息
        try:
            global producer
            # 判断通道是否关闭
            if producer.is_closed:
                # 关闭了就重新创建一个
                producer = getWriteChannel() # 这里是创建通道,只是封装了
            producer.basic_publish(exchange=WRITE_EXCHANGE,routing_key=ROUTING_KEY,body=val)
        except Exception as e:
            # 异常补偿,关闭后重新创建并将消息重新放回去
            producer.close()
            producer = getWriteChannel()
            writeQueue.put(val)

# 开启线程
threading.Thread(target=writeBack,name=str(THREAD_COUNT)).start()  

B、开启多个任务实际干活速度没有提上来?

抛开实际的运行瓶颈,资源数量,有可能是没有设置预读取数量。默认预读取数量时全部,这样会导致一个mq任务启动后直接读取全部消息而其他任务无消息可读。

# 就是这句话
readConnection.basic_qos(prefetch_count=1)
# 加在这段代码上面就可以了
# channel.basic_consume()
# channel.start_consuming()

本文作者:Ch1ee

本文链接:https://www.cnblogs.com/daimourentop/p/17605355.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Ch1ee  阅读(147)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起