• python中利用redis构建任务队列(queue)


    Python中的使用标准queue模块就可以建立多进程使用的队列,但是使用redisredis-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/<job_key>', 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返回值
  • 相关阅读:
    我要好offer之 二叉树大总结
    我要好offer之 字符串相关大总结
    楼层扔鸡蛋问题[转]
    Linux System Programming 学习笔记(十一) 时间
    Linux System Programming 学习笔记(十) 信号
    Linux System Programming 学习笔记(九) 内存管理
    Linux System Programming 学习笔记(八) 文件和目录管理
    Linux System Programming 学习笔记(七) 线程
    Linux System Programming 学习笔记(六) 进程调度
    APUE 学习笔记(十一) 网络IPC:套接字
  • 原文地址:https://www.cnblogs.com/zlel/p/10271972.html
Copyright © 2020-2023  润新知