Redis队列简单应用-Python
@[redis|队列|异步任务|python]
大家通常会有这样需求,当我在一个web api中我想要去发送一个邮件,发送一个短信, 下发一个特别耗时的任务的时候,往往想到的是建一个celery吧,今天来说一下自己写一个简单redis队列异步任务worker。
Redis队列模式介绍
Redis的队列模式有两种应用:
1.生产消费模式:N个worker同时抢任务,适用于发邮件,发短信
2.订阅发布模式:N个worker同时都得到这个任务,适用于一个数据要存到多个地方去
生产消费者模式
这个用的是redis的 lpush 和 brpop 具体的逻辑看代码
worker端 (work.py):
import redis, json
r = redis.StrictRedis(host="localhost", port=6379, db=0)
def listen():
while True:
data = r.brpop("test:worker:push")
run(json.loads(data[1]))
def run(data):
print data
if __name__ == '__main__':
listen()
client端 (client.py):
import redis, json
r = redis.StrictRedis(host="localhost", port=6379, db=0)
def send_task(num):
task_data = json.dumps({
"name": "Jack",
"age": 16,
"num": num
})
r.lpush("test:worker:push", task_data)
if __name__ == '__main__':
for i in range(10):
send_task(i)
执行 我启动了两个worker 然后client发送了10次任务, 输出如下:
worker1:
{u'age': 16, u'num': 0, u'name': u'Jack'}
{u'age': 16, u'num': 2, u'name': u'Jack'}
{u'age': 16, u'num': 3, u'name': u'Jack'}
{u'age': 16, u'num': 6, u'name': u'Jack'}
{u'age': 16, u'num': 8, u'name': u'Jack'}
worker2:
{u'age': 16, u'num': 1, u'name': u'Jack'}
{u'age': 16, u'num': 4, u'name': u'Jack'}
{u'age': 16, u'num': 5, u'name': u'Jack'}
{u'age': 16, u'num': 7, u'name': u'Jack'}
{u'age': 16, u'num': 9, u'name': u'Jack'}
发布订阅模式
这里使用的是Redis pub/sub 的功能
worker端 (worker.py):
# -*- coding: utf-8 -*-
# @Author: lxstar
# @Date: 2017-04-26 11:09:41
# @Last Modified by: lxstar
# @Last Modified time: 2017-04-26 11:49:02
import redis, json
r = redis.StrictRedis(host="localhost", port=6379, db=0)
def listen():
channel = "test:worker:pubsub"
ps = r.pubsub()
ps.subscribe(channel) # 还可以订的多个频道 同时也能发布多个频道
# ps.subscribe(["channel_1", "channel_2"])
while True:
for item in ps.listen():
if item["channel"] == channel
if item["type"] == "message":
run(json.loads(item["data"]))
def run(data):
print data
if __name__ == '__main__':
listen()
client端 (client.py):
# -*- coding: utf-8 -*-
# @Author: lxstar
# @Date: 2017-04-26 11:11:25
# @Last Modified by: lxstar
# @Last Modified time: 2017-04-26 11:33:09
import redis, json
r = redis.StrictRedis(host="localhost", port=6379, db=0)
def send_task(num):
task_data = json.dumps({
"name": "Jack",
"age": 16,
"num": num
})
r.publish("test:worker:pubsub", task_data)
if __name__ == '__main__':
for i in range(3):
send_task(i)
执行 我启动了两个worker 然后client发送了3次任务, 输出如下:
worker1:
{u'age': 16, u'num': 0, u'name': u'Jack'}
{u'age': 16, u'num': 1, u'name': u'Jack'}
{u'age': 16, u'num': 2, u'name': u'Jack'}
worker2:
{u'age': 16, u'num': 0, u'name': u'Jack'}
{u'age': 16, u'num': 1, u'name': u'Jack'}
{u'age': 16, u'num': 2, u'name': u'Jack'}
尾巴
有的时候,发送邮件之类的需求,其实并不需要去等待处理的结果如何,异步任务往往是最佳的选择。当你不想上celery之类的框架,或者你的事情特别简单的话,可以尝试这种方式去做这样一个简单的worker。
关于部署,推荐使用supervisord之类的工具,启动多个或者管理状态都是极好的。
关于稳定性,线上的推送/邮件/短信,都是基于这个在跑着,大半年了没出过状况,但只是我的场景实践,仅供参考。
如果你还需要知道执行的结果和监控任务执行的进度的话,想必celery是极好的。
更多干货内容,欢迎关注公众号:知了python