python 实现 延时队列

python 实现 延时队列

# 延时队列
import threading
import functools
import queue
import datetime



def test():
    print("执行成功")


def seconds_chagne(dt):
    return dt.seconds + dt.days * 24 * 60 * 60


# 延迟任务类
class DelayTask:
    # delay_time 即将过期的时间
    # task 参与延迟的任务
    def __init__(self,delay_time,job_func):
        self.delay_time = delay_time
        self.job_func = job_func


# 延迟队列
class DelayQueue(queue.PriorityQueue):
    def __init__(self):
        self.can_done = threading.Condition()
        # Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。

        # 首先acquire一个条件变量,然后判断一些条件。
        # 如果条件不满足则wait;
        # 如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。
        # 不断的重复这一过程,从而解决复杂的同步问题
        super(DelayQueue, self).__init__()


    # 入队操作
    def task_put(self,task):
        # 存入元组 (任务的过期时间,当前任务)
        self.put((task.delay_time,task))


    # 获取队顶数据
    def _peek(self):
        self.not_empty.acquire()
        try:
            # 判断队列是否为空
            while not self._qsize():
                # 为空就等待
                self.not_empty.wait()
            return self.queue[0][1]
        finally:
            self.not_empty.release()


    # 出队
    def get_task(self):
        # 获取锁
        self.can_done.acquire()
        try:
            # 获取队顶数据
            task = self._peek()
            # 判断是否到达过期时间(延迟时间)
            delta = seconds_chagne(task.delay_time - datetime.datetime.now())
            while delta > 0:
                # 等待
                self.can_done.acquire(delta)
                # 获取任务
                task = self._peek()
                delta = seconds_chagne(task.delay_time - datetime.datetime.now())
            # 出队
            item = self.get()
            self.can_done.notify_all()
            return item[1]
        finally:
            # 释放锁
            self.can_done.release()


# 声明装饰任务
task = functools.partial(test)
# 声明延时任务
task_delay = DelayTask(delay_time=datetime.datetime.now()+datetime.timedelta(seconds=3),job_func=task)
# 实例化队列
delay_queue = DelayQueue()
# 入队
delay_queue.task_put(task_delay)
# 出队
res = delay_queue.get_task()
# 执行方法
res.job_func()

基于redis写的延时队列(有序集合)

import redis

class DelayRedisQueue:
    def __init__(self,key):
        self.key = key
        self.r = redis.Redis(decode_responses=True)


    # 入队
    def add(self,uid,delay_time=0):
        print("延时队列入队,%s秒后执行删除uid%s的任务" % (delay_time,uid))
        self.r.zadd(self.key,{uid:time.time()+delay_time})


    # 删除延时任务
    def remove(self,uid):
        return self.r.zrem(self.key,uid)


    # 出队
    def pop(self):
        # 起始位置
        min_score = 0
        # 区间结束位置
        max_score = time.time()
        # 获取队列
        res = self.r.zrangebyscore(self.key,min_score,max_score,start=0,num=1,withscores=False)
        if res == None:
            print("暂无延时任务")
            return False
        if len(res) == 1:
            print("延时任务到期,返回执行任务的uid%s"% res[0])

            return res[0]

        else:
            print("延时任务没有到时间")
            return False

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Redis 中,可以使用有序集合(zset)来实现延时队列延时队列的基本原理是将元素添加到有序集合中,并使用元素的分数(score)表示元素需要被执行的时间戳。以下是实现延时队列的一些关键步骤: 1. 将元素添加到有序集合中:使用 ZADD 命令将元素添加到有序集合中,同时设置元素的分数为需要执行的时间戳。 2. 获取需要执行的元素:使用 ZRANGEBYSCORE 命令,设置分数范围为当前时间戳及之前的某个时间,获取需要执行的元素。可以使用 withscores 选项来返回元素及其分数。 3. 执行元素操作:根据具体的业务逻辑,执行需要执行的元素的操作。 4. 移除已执行的元素:使用 ZREM 命令,将已执行的元素从有序集合中移除。 以下是一个使用 Python Redis 模块实现延时队列的示例代码: ```python import redis import time def add_delayed_element(redis_conn, element, delay): timestamp = int(time.time()) + delay redis_conn.zadd('delayed_queue', {element: timestamp}) def process_delayed_elements(redis_conn): current_timestamp = int(time.time()) elements = redis_conn.zrangebyscore('delayed_queue', 0, current_timestamp) for element in elements: # 执行元素操作 print(f"Processing element: {element}") # 移除已执行的元素 redis_conn.zrem('delayed_queue', element) # 创建 Redis 连接 redis_conn = redis.Redis(host='localhost', port=6379, db=0) # 添加延时元素 add_delayed_element(redis_conn, 'element1', 10) add_delayed_element(redis_conn, 'element2', 5) # 处理延时元素 process_delayed_elements(redis_conn) ``` 通过上述示例代码,你可以使用 Redis 的有序集合实现简单的延时队列功能。注意,在实际应用中,你可能需要考虑一些额外的因素,如元素的优先级、重试机制等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值