消息可以理解为任务,消息发送者可以看成任务派送者(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的使用(工作队列)的更多相关文章

  1. python中RabbitMQ的使用(安装和简单教程)

    1,简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从"生产者"接收消息 ...

  2. python中RabbitMQ的使用(远程过程调用RPC)

    在RabbitMQ消息队列中,往往接收者.发送者不止是一个身份.例如接接收者收到消息并且需要返回给发送者. 此时接收者.发送者的身份不再固定! 我们来模拟该情形: 假设有客户端client,服务端se ...

  3. python中RabbitMQ的使用(交换机,广播形式)

    简介 如果要让每个接收端都能收到消息,此时需要将消息广播出去,需要使用交换机. 工作原理 消息发送端先将消息发送给交换机,交换机再将消息发送到绑定的消息队列,而后每个接收端都能从各自的消息队列里接收到 ...

  4. python中RabbitMQ的使用(路由键模糊匹配)

    路由键模糊匹配 使用正则表达式进行匹配.其中“#”表示所有.全部的意思:“*”只匹配到一个词. 匹配规则: 路由键:routings = [ 'happy.work',  'happy.life' , ...

  5. python中RabbitMQ的使用(路由键)

    1.简介 当我们希望每个接收端接收各自希望的消息时,我们可以使用路由键,此时交换机的类型为direct. 2.工作原理 每个接收端的消息队列在绑定交换机的时候,可以设定相应的路由键. 发送端通过交换机 ...

  6. rabbitmq(中间消息代理)在python中的使用

    在之前的有关线程,进程的博客中,我们介绍了它们各自在同一个程序中的通信方法.但是不同程序,甚至不同编程语言所写的应用软件之间的通信,以前所介绍的线程.进程队列便不再适用了:此种情况便只能使用socke ...

  7. 十一天 python操作rabbitmq、redis

    1.启动rabbimq.mysql 在""运行""里输入services.msc,找到rabbimq.mysql启动即可 2.启动redis 管理员进入cmd, ...

  8. python操作rabbitmq、redis

    1.启动rabbimq.mysql 在“”运行“”里输入services.msc,找到rabbimq.mysql启动即可 2.启动redis 管理员进入cmd,进入redis所在目录,执行redis- ...

  9. Python操作RabbitMQ

    RabbitMQ介绍 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从“生产者”接收消息并传递消 ...

随机推荐

  1. 3、My Scripts

    .用for循环批量修改文件扩展名(P240) .使用专业改名命令rename来实现 .通过脚本实现sshd.rsyslog.crond.network.sysstat服务在开机时自动启动(P244) ...

  2. 在服务器端对sshd做白名单

    1.添加用户 #useradd aaa #passwd aaa -->输入密码:123456 添加3个用户,bbb和ccc与aaa添加一样 2.添加白名单 #vim /etc/ssd/sshd_ ...

  3. 《机器学习实战》之k-近邻算法(手写识别系统)

    这个玩意和改进约会网站的那个差不多,它是提前把所有数字转换成了32*32像素大小的黑白图,然后转换成字符图(用0,1表示),将所有1024个像素点用一维矩阵保存下来,这样就可以通过knn计算欧几里得距 ...

  4. BZOJ 1143: [CTSC2008]祭祀river(二分图最大点独立集)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1143 题意: 思路: 二分图最大点独立集,首先用floyd判断一下可达情况. #include< ...

  5. JMeter中关于动态切换不同CSV文件解决方案

    最近写case,需要当前播放节目的数据作为输入数据,所以每个时刻所用的数据只能是当前时刻附件的数据,尝试用CSV Data Set Config动态加载不同的文件,没有成功,好像CSV Data Se ...

  6. OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000083e80000, 1366294528, 0) failed;

    我是在手动搭建nexus时遇到的 安装nexus时 启动命令的时候会报OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000 ...

  7. ERP系统知识笔记

    中心思想: 1.不管哪一家的ERP系统,都是以“平衡供需”为目的.以计划为中心思想的,并将各管理职能作紧密的集成 2.手工管理方式下,对库存量的掌握是不完整的.手工方式下,我们的数据只有现存量,无法记 ...

  8. python 操作剪切板

    python3 在使用网上找到的一些使用剪切板的片段时发现存在写入剪切板后乱码的情况, 研究后发现python3不能使用SetClipboardData方法, 要使用SetClipboardText ...

  9. Java创建多线程和线程安全集合Vector

    public class Test { public static Vector<String> data = new Vector<String>(); public sta ...

  10. (9)进程---JoinableQueue队列

    消费者模型-->存和取得过程 和Queue队列区别:解决了Queue队列拿取完,程序阻塞不能自动关闭(依靠放入None来解决)的问题--->参见上个例子 put 存入, get 获取 q. ...