python中RabbitMQ的使用(工作队列)
消息可以理解为任务,消息发送者可以看成任务派送者(sender),消息接收者可以看成工作者(worker)。
当工作者接收到一个任务,还没完任务时分配者又发一个任务,此时需要多个工作者来共同处理这些任务。
任务分派结构图如下:
注:此时有一个任务派送人P,两个工作接收者C1和C2。
现在我们来模拟该情况:
1.首先打开三个终端:
2.分别在前两个终端运行receive1.py
3.在第三个终端多次运行send1.py
此时将会轮流向worker1和worker2分派任务。
问题:
在以上任务分配和完成情况中,有几个问题将会产生:
1.工作者任务是否完成?
2.工作者挂掉后,如何防止未完成的任务丢失,并且如何处理这些任务?
3.RabbitMQ自身出现问题,此时如何防止任务丢失?
4.任务有轻重之分,如何实现公平调度?
方案:
1.消息确认(Message acknowledgment)
当任务完成后,工作者(receiver)将消息反馈给RabbitMQ:
def callback(ch, method, properties, body):
print " [x] Received %r" % (body,)
#停顿5秒,方便ctrl+c退出
time.sleep(5)
print " [x] Done"
#当工作者完成任务后,会反馈给rabbitmq
ch.basic_ack(delivery_tag=method.delivery_tag)
2.保留任务(no_ack=False)
当工作者挂掉后,防止任务丢失:
# 去除no_ack=True参数或者设置为False后可以实现
# 一个工作者ctrl+c退出后,正在执行的任务也不会丢失,rabbitmq会将任务重新分配给其他工作者。
channel.basic_consume(callback, queue='task_queue', no_ack=False)
3.消息持久化存储(Message durability)
声明持久化存储:
# durable=True即声明持久化存储
channel.queue_declare(queue='task_queue', durable=True)
在发送任务时,用delivery_mode=2来标记任务为持久化存储:
# 用delivery_mode=2来标记任务为持久化存储:
channel.basic_publish(exchange='',
routing_key='task_queue',
body=message,
properties=pika.BasicProperties(
delivery_mode=2,
))
4.公平调度(Fair dispatch)
使用basic_qos设置prefetch_count=1,使得rabbitmq不会在同一时间给工作者分配多个任务,即只有工作者完成任务之后,才会再次接收到任务
channel.basic_qos(prefetch_count=1)
完整代码如下:
receive1.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pika
import time hostname = '192.168.1.133'
parameters = pika.ConnectionParameters(hostname)
connection = pika.BlockingConnection(parameters) # 创建通道
channel = connection.channel()
# durable=True后将任务持久化存储,防止任务丢失
channel.queue_declare(queue='task_queue', durable=True) # ch.basic_ack为当工作者完成任务后,会反馈给rabbitmq
def callback(ch, method, properties, body):
print " [x] Received %r" % (body,)
time.sleep(5)
print " [x] Done"
ch.basic_ack(delivery_tag=method.delivery_tag) # basic_qos设置prefetch_count=1,使得rabbitmq不会在同一时间给工作者分配多个任务,
# 即只有工作者完成任务之后,才会再次接收到任务。
channel.basic_qos(prefetch_count=1) 27 # 去除no_ack=True参数或者设置为False后可以实现
28 # 一个工作者ctrl+c退出后,正在执行的任务也不会丢失,rabbitmq会将任务重新分配给其他工作者。
channel.basic_consume(callback, queue='task_queue', no_ack=False)
# 开始接收信息,按ctrl+c退出
print ' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()
send1.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pika
import random hostname = '192.168.1.133'
parameters = pika.ConnectionParameters(hostname)
connection = pika.BlockingConnection(parameters) # 创建通道
channel = connection.channel()
# 如果rabbitmq自身挂掉的话,那么任务会丢失。所以需要将任务持久化存储起来,声明持久化存储:
channel.queue_declare(queue='task_queue', durable=True) number = random.randint(1, 1000)
message = 'hello world:%s' % number # 在发送任务的时候,用delivery_mode=2来标记任务为持久化存储:
channel.basic_publish(exchange='',
routing_key='task_queue',
body=message,
properties=pika.BasicProperties(
delivery_mode=2,
))
print " [x] Sent %r" % (message,)
connection.close()
示例如下:
首先启动三个终端,两个先执行receive1.py,第三个多次执行rend1.py:
终端3:
此时分配三个任务,33分配给worker1,170分配给worker2,262分配给worker1
终端1:
worker1完成任务33后,开始任务262,我们在任务完成前使用(CRTL+C)使worker1挂掉
终端2:
worker2完成任务170,本来没有任务,但是worker1挂掉,此时接收他的任务262
python中RabbitMQ的使用(工作队列)的更多相关文章
- python中RabbitMQ的使用(安装和简单教程)
1,简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从"生产者"接收消息 ...
- python中RabbitMQ的使用(远程过程调用RPC)
在RabbitMQ消息队列中,往往接收者.发送者不止是一个身份.例如接接收者收到消息并且需要返回给发送者. 此时接收者.发送者的身份不再固定! 我们来模拟该情形: 假设有客户端client,服务端se ...
- python中RabbitMQ的使用(交换机,广播形式)
简介 如果要让每个接收端都能收到消息,此时需要将消息广播出去,需要使用交换机. 工作原理 消息发送端先将消息发送给交换机,交换机再将消息发送到绑定的消息队列,而后每个接收端都能从各自的消息队列里接收到 ...
- python中RabbitMQ的使用(路由键模糊匹配)
路由键模糊匹配 使用正则表达式进行匹配.其中“#”表示所有.全部的意思:“*”只匹配到一个词. 匹配规则: 路由键:routings = [ 'happy.work', 'happy.life' , ...
- python中RabbitMQ的使用(路由键)
1.简介 当我们希望每个接收端接收各自希望的消息时,我们可以使用路由键,此时交换机的类型为direct. 2.工作原理 每个接收端的消息队列在绑定交换机的时候,可以设定相应的路由键. 发送端通过交换机 ...
- rabbitmq(中间消息代理)在python中的使用
在之前的有关线程,进程的博客中,我们介绍了它们各自在同一个程序中的通信方法.但是不同程序,甚至不同编程语言所写的应用软件之间的通信,以前所介绍的线程.进程队列便不再适用了:此种情况便只能使用socke ...
- 十一天 python操作rabbitmq、redis
1.启动rabbimq.mysql 在""运行""里输入services.msc,找到rabbimq.mysql启动即可 2.启动redis 管理员进入cmd, ...
- python操作rabbitmq、redis
1.启动rabbimq.mysql 在“”运行“”里输入services.msc,找到rabbimq.mysql启动即可 2.启动redis 管理员进入cmd,进入redis所在目录,执行redis- ...
- Python操作RabbitMQ
RabbitMQ介绍 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从“生产者”接收消息并传递消 ...
随机推荐
- 为什么返回的数据前面有callback?
这是一个同学出现的问题,问到了我. 应该是这样的: 但问题是这样的: 我看了所请求的格式和后台要求的也是相同的.而且我也是这种做法,为什么他的就不行呢? 打了几遍 JSON.parse 也都是不行…… ...
- Centos6.5 搭建LAMP环境
1.Centos6.5 处于对安全的考虑,严格控制网络的进去.所以安装 Apache 或 MySQL 的时候,需要开放 80 或 3306 端口 首先,执行如下命令查看当前防火墙开放了哪些端口: [ ...
- Spring boot2.0 与 2.0以前版本 跨域配置的区别
一·简介 spring boot升级到2.0后发现继承WebMvcConfigurerAdapter实现跨域过时了,那我们就紧随潮流. 二·全局配置 2.0以前 支持跨域请求代码: import or ...
- [原][osgEarth][JSBSim]重新整理使用JSBSim飞机动力模拟的使用
JSBSim是一个模拟飞机飞行空气动力学的,这些都不用深入理解,只要知道自己程序怎么和JSBSim交互就行了 我使用的是JSBSim-Win32-0.9.13 原理:改写jsbsim的FGInput ...
- Grunt、Gulp区别 webpack、 requirejs区别
1. 书写方式 grunt 运用配置的思想来写打包脚本,一切皆配置,所以会出现比较多的配置项,诸如option,src,dest等等.而且不同的插件可能会有自己扩展字段,导致认知成本的提高,运用的时候 ...
- npm i和npm install的区别
最近人用npm i来直接安装模块,但是有会报错,用npm install就不会报错,刚开始百思不得其解,它俩明明是同一个东西 后来查npm的帮助指令发现还是没区别,npm i仅仅是npm instal ...
- H5多媒体(用面向对象的方法控制视频、音频播放、暂停、延时暂停)
视频,音频播放器会是我们在工作中用到的一些h5新标签,它自带一些属性,比如暂停播放,快进快退,但是,我们经常不用原生的样式或者方法,我们需要自定义这些按钮来达到我们需要的样式,也需要我们自定义来实现一 ...
- RestTemplate学习
在学习spring cloud的时候,用到了RestTemplate,找到一篇博客,写的很好,学习转载! 文章转载自:https://blog.csdn.net/itguangit/article/d ...
- echart 圆滑初始化化
圆滑:主题下载对应主题js引入后注入对应名称参数方可使用主题 初始化:tab点击的时候初始化图表涉及到tab切换到的需要延迟加载否则默认宽度为100px 1.创建macarons.js文件 2.页面添 ...
- alfred
1.alfred怎么设置默认的搜索项. https://www.zhihu.com/question/20205127 2.