使用Redis构建任务队列
文章目录
- 第1关:先进先出任务队列
- 第2关:优先级任务队列
- 第3关:定时任务队列
第1关:先进先出任务队列
编程要求
在Begin-End区域编写 add_task(task_name) 函数,实现将任务加入队列的功能,具体参数与要求如下:
方法参数 task_name 是要加入的任务名称;
推入任务的实现:将新的任务从列表 task:list 的尾部插入。
编写 pop_task() 函数,实现获取一个任务的功能,具体参数与要求如下:
获取任务的实现:从列表 task:list 的头部阻塞式的弹出一个值,最长等待10秒,若超时仍未获取到,则重试该操作,直至弹出一个值;
任务返回的实现:获取任务成功后,返回该值中弹出的元素值。
测试说明
平台会对你编写的代码进行测试:
测试输入:my_task;
预期输出:
测试 add_task 方法…
推入任务:my_task
当前任务队列:[‘my_task’]
测试 pop_task 方法…
出队列任务:my_task
当前任务队列:[]
在多线程下测试队列工作…
出队列任务:new task
代码示例如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import redis
conn = redis.Redis()
# 将任务加入队列
def add_task(task_name):
# 请在下面完成要求的功能
#********* Begin *********#
conn.rpush("task:list",task_name)
#********* End *********#
# 获取一个任务
def pop_task():
# 请在下面完成要求的功能
#********* Begin *********#
while True:
task = conn.blpop("task:list",10)
if not task:
continue
return task[1]
#********* End *********#
第2关:优先级任务队列
编程要求
在Begin-End区域编写 add_task_list(list_name, priority) 函数,实现设置任务队列优先级的功能,具体参数与要求如下:
方法参数 list_name 是要加入的任务队列名字,priority 是要设置的优先权重,值越大则级别越高;
设置队列优先级的实现:为了能按照优先权重排列任务队列,将任务队列加入到有序集合 task:priority 中,分值为 priority。
编写 add_task(list_name, task_name) 函数,实现将任务加入队列的功能,具体参数与要求如下:
方法参数 list_name 是要加入的任务队列名字,task_name 是要加入的任务名称;
推入任务的实现:将新的任务从指定的列表尾部插入。
编写 pop_task()函数,实现获取一个任务的功能,具体参数与要求如下:
排序任务队列的实现:将有序集合 task:priority 中的所有成员按照分值递减的顺序排列;
获取任务的实现:按照上述队列的顺序,从第一个非空列表的头部阻塞式的弹出一个值,最长等待10秒,若超时仍未获取到,则重试该操作,直至弹出一个值;
任务返回的实现:获取任务成功后,返回该值中弹出的元素值。
测试说明
平台会对你编写的代码进行测试:
测试输入:h,e,l,o,d,u,c,r;
预期输出:
测试 add_task_list 方法…
加入三个任务队列:[‘task:list:high’, ‘task:list:mid’, ‘task:list:low’]
测试 add_task 方法…
推入任务:h 到 task:list:high
推入任务:e 到 task:list:mid
推入任务:l 到 task:list:low
推入任务:o 到 task:list:high
推入任务:d 到 task:list:mid
推入任务:u 到 task:list:low
推入任务:c 到 task:list:high
推入任务:r 到 task:list:mid
当前 task:list:high 任务队列:[‘h’, ‘o’, ‘c’]
当前 task:list:mid 任务队列:[‘e’, ‘d’, ‘r’]
当前 task:list:low 任务队列:[‘l’, ‘u’]
测试 pop_task 方法…
出队列顺序:[‘h’, ‘o’, ‘c’, ‘e’, ‘d’, ‘r’, ‘l’, ‘u’]
当前 task:list:high 任务队列:[]
当前 task:list:mid 任务队列:[]
当前 task:list:low 任务队列:[]
在多线程下测试队列工作…
出队列任务:new task
代码示例如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import redis
conn = redis.Redis()
# 新建任务队列/改变任务队列优先级
def add_task_list(list_name, priority):
# 请在下面完成要求的功能
#********* Begin *********#
conn.zadd("task:priority",list_name,priority)
#********* End *********#
# 将任务加入队列
def add_task(list_name, task_name):
# 请在下面完成要求的功能
#********* Begin *********#
conn.rpush(list_name,task_name)
#********* End *********#
# 获取一个任务
def pop_task():
# 请在下面完成要求的功能
#********* Begin *********#
while True:
task = conn.blpop(conn.zrevrange("task:priority",0,-1),10)
if not task:
continue
return task[1]
#********* End *********
第3关:定时任务队列
编程要求
在Begin-End区域编写 execute_later(task_name, delay=0) 函数,实现添加定时任务的功能,具体参数与要求如下:
方法参数 task_name 是要加入的任务名称,delay 是任务的延迟时间;
添加定时任务的实现:若延迟时间大于0,则将任务加入到有序集合 task:delayed 中,分值为任务的执行时间,等于当前时间戳加上延迟时间;
添加普通任务的实现:若延迟时间小于等于0,则将其插入到列表task:list的尾部。
编写 pop_task() 函数,实现转移可执行任务的功能,具体参数与要求如下:
获取队列中第一个任务的实现:不断尝试获取有序集合task:delayed中按分值递增顺序的第一个元素;
判断该任务是否可执行的实现:若未取到任务或者任务的执行时间未到,则休眠 0.01 秒,然后继续尝试获取第一个任务;
任务转移的实现:从有序集合task:delayed中移除该任务,成功后,将该任务插入到列表task:list的尾部。
测试说明
平台会对你编写的代码进行测试:
测试输入:无;
预期输出:
测试 execute_later 方法…
添加任务,task-0 ,延迟:0
添加任务,task-1 ,延迟:0.5
添加任务,task-2 ,延迟:0
添加任务,task-3 ,延迟:1.5
普通任务队列长度:2
定时执行任务队列内容:[‘task-1’, ‘task-3’]
测试 pop_task 方法…
等待0.6秒后,普通任务队列长度为:3
普通任务队列内容为:[‘task-0’, ‘task-2’, ‘task-1’]
等待1.6秒后,普通任务队列长度为:4
普通任务队列内容为:[‘task-0’, ‘task-2’, ‘task-1’, ‘task-3’]
代码示例如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import time
import redis
conn = redis.Redis()
# 添加定时任务
def execute_later(task_name, delay=0):
# 请在下面完成要求的功能
#********* Begin *********#
if delay > 0:
conn.zadd("task:delayed",task_name,time.time()+delay)
else:
conn.rpush("task:list",task_name)
#********* End *********#
# 转移可执行任务
def pop_task():
# 请在下面完成要求的功能
#********* Begin *********#
while True:
task = conn.zrange("task:delayed",0,0,withscores=True)
if not task or task[0][1] > time.time():
time.sleep(0.01)
continue
task = task[0][0]
if conn.zrem("task:delayed",task):
conn.rpush("task:list",task)
#********* End *********#