python redis 消息队列_python中利用redis构建任务队列(queue)

Python中的使用标准queue模块就可以建立多进程使用的队列,但是使用redis和redis-queue(rq)模块使这一操作更加简单。

Part 1.

比如首先我们使用队列来简单的储存数据:我们选用redis list类型,其他类型的数据操作可以参考这个文章

在redis_queue.py文件中:

import redis

class RedisQueue(object):

def __init__(self, name, namespace='queue', **redis_kwargs):

# redis的默认参数为:host='localhost', port=6379, db=0, 其中db为定义redis database的数量

self.__db= redis.Redis(**redis_kwargs)

self.key = '%s:%s' %(namespace, name)

def qsize(self):

return self.__db.llen(self.key) # 返回队列里面list内元素的数量

def put(self, item):

self.__db.rpush(self.key, item) # 添加新元素到队列最右方

def get_wait(self, timeout=None):

# 返回队列第一个元素,如果为空则等待至有元素被加入队列(超时时间阈值为timeout,如果为None则一直等待)

item = self.__db.blpop(self.key, timeout=timeout)

# if item:

# item = item[1] # 返回值为一个tuple

return item

def get_nowait(self):

# 直接返回队列第一个元素,如果队列为空返回的是None

item = self.__db.lpop(self.key)

return item

在input.py文件中:

from redis_queue import RedisQueue

import time

q = RedisQueue('rq') # 新建队列名为rq

for i in range(5):

q.put(i)

print "input.py: data {} enqueue {}".format(i, time.strftime("%c"))

time.sleep(1)

在output.py文件中:

from redis_queue import RedisQueue

import time

q = RedisQueue('rq')

while 1:

result = q.get_nowait()

if not result:

break

print "output.py: data {} out of queue {}".format(result, time.strftime("%c"))

time.sleep(2)

在test_run.sh文件中:

python input.py &

python output.py &

在terminal中运行test.sh的结果如下:

input.py: data 0 enqueue Fri Nov 10 10:51:37 2017

output.py: data 0 out of queue Fri Nov 10 10:51:37 2017

input.py: data 1 enqueue Fri Nov 10 10:51:38 2017

output.py: data 1 out of queue Fri Nov 10 10:51:38 2017

input.py: data 2 enqueue Fri Nov 10 10:51:39 2017

output.py: data 2 out of queue Fri Nov 10 10:51:39 2017

input.py: data 3 enqueue Fri Nov 10 10:51:40 2017

output.py: data ('queue:rq', '3') out of queue Fri Nov 10 10:51:40 2017

input.py: data 4 enqueue Fri Nov 10 10:51:41 2017

output.py: data ('queue:rq', '4') out of queue 1510282301.69

其中lpop返回的是一个队列名+元素值的tuple,并且返回的数值默认为string

Part 2.

队列里面可以添加任意object,因此可以添加函数到多个队列来实现多线程并发的效果。

首先,建立一个rq work进程(写在worker.py脚本中)来监听队列

import redis

from rq import Worker, Queue, Connection

listen = ['default']

redis_url = "redis://localhost:6379" # redis server 默认地址

conn = redis.from_url(redis_url)

def square_function(x):

return x*x

if __name__ == '__main__':

with Connection(conn): # 建立与redis server的连接

worker = Worker(list(map(Queue, listen))) # 建立worker监听给定的队列

worker.work()

然后python worker.py启动redis server

在test.py文件中:

from rq import Queue

from rq.job import Job

from worker import square_function, conn

import time

q = Queue(connection=conn)

job = q.enqueue_call(square_function, args=(5, ), result_ttl=5000) # 保存结果5000s

job_id = job.get_id()

print job_id

result1 = Job.fetch(job_id, connection=conn)

print result1.is_finished

time.sleep(1) # 等待队列里任务完成

result2 = Job.fetch(job_id, connection=conn)

print result2.return_value

上面文件的输出结果为:

98dc6f58-9333-48f7-88c1-c4de1cc9e5cf # job id

False # 任务尚未完成

25 # 任务完成,输出结果

注: 调用的square_function不允许和任务发起在同一个脚本,否则会报错ValueError: Functions from the __main__ module cannot be processed by workers

当与flask一起使用时:

在app.py文件中:

from rq import Queue

from rq.job import Job

from worker import conn, square_function

from flask import Flask, request

app = Flask(__name__)

q = Queue(connection=conn) # 建立与Redis server的连接并初始化一个队列

@app.route("/", methods=['POST'])

def index():

x = request.get_data() # string 类型

job = q.enqueue_call(square_function, args=(int(x), ), result_ttl=5000) # 最后的参数为RQ保留结果的时间

return job.get_id() # 返回job的id

@app.route('/result/', methods=['GET'])

def get_results(job_key):

job = Job.fetch(job_key, connection=conn) # 获取根据job_id获取任务的返回值

if job.is_finished: # 检验是否完成

return str(job.result), 200

else:

return "Wait!", 202

if __name__ == "__main__":

app.run('0.0.0.0', port=5000)

python app.py启动flask服务

在test.py文件:

import requests

import time

post_url = "http://localhost:5000"

post_result = requests.post(post_url, data={'x': 2})

job_id = post_result.content

print job_id

time.sleep(1)

get_url = "http://localhost:5000/result/{}".format(job_id)

get_result = requests.get(get_url)

print get_result.content

获得的结果如下:

067306e9-f13b-4b6a-93dc-2f5b457a78b7 # job id

4 # job返回值

参考:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值