zoukankan      html  css  js  c++  java
  • PHP怎样写延时队列(定时器)

    背景

    PHP没有定时器,依托的都是crontab这样的系统工具,也没有go中defer这样的延时方法,本文介绍几种PHP写延时队列的几种姿势。

    延时队列的定义

    普通的队列是先进先出,但是延时队列并不是,而是加上了时间这一权重。希望到达时间点的先执行。

    从某种意义上来讲,延迟队列的结构并不像一个队列,而更像是一种以时间为权重的有序堆结构。

    Hash

    将key使用一个唯一标识,保证每个任务都不重复,也方便删除,然后value中添加需要调用的函数名和时间戳,以及参数。
    没秒进行遍历,然后将时间到的取出来执行,再删除。

    入队:hSet key:uuid value:{timestamp,function,param}
    出队:timestamp > now do function(param)

    问题很明显,需要遍历,hGetAll是禁忌法术。

    ZSet

    前面谈到了,其实延时队列就是一种有序堆结构,就是需要加上一个时间权重,那么,有序集合不就是这样的么?

    入队:ZADD KEY timestamp task ,我们将需要处理的任务,按其需要延迟处理时间作为 Score 加入到 ZSet 中。
    出队:ZRANGEBYSCORE KEY -inf +inf limit 0 1 WITHSCORES。这样就能取出需要执行的任务了。执行完后删除:Zremrangebyscore KEY -inf +inf limit

    时间轮

    其实以上的算法,都有个小问题,同一时间线的任务先后问题,比如都是凌晨00执行的,怎么谁先谁后?因为任务是有优先级或者顺序的,当然也可以按优先级设置多个key,思路有很多。

    这里在介绍一种算法,也是很多消息队列软件使用的,时间轮算法。

    其实也很简单,就是每个时间点放一个队列,然后用一个任务去扫描时间轮,就像时钟一样,这样就能到点执行对应的任务了。

    图片来源于网络

    比如任务扫描到了2,需要添加一个延时3秒的任务,就直接添加到5上面。

    当然对于时间粒度不同,我们肯定要设置多个时间轮,就像时针分针秒针。

    这样的好处是什么?

    • 前面两种方式,说到底,需要遍历+排序,而时间轮,只需要逐步扫描逐步取出任务就好了。效率上高了很多,任务越多越明显。
  • 相关阅读:
    洛谷P1170 兔八哥与猎人 欧拉函数的应用
    洛谷P1056 排座椅
    洛谷P1177 【模板】快速排序
    洛谷1059 明明的随机数
    洛谷P1372 又是毕业季I
    洛谷P1042 乒乓球
    洛谷P1086 花生采摘
    洛谷P1031 均分纸牌
    洛谷P1068 分数线划定
    洛谷P1781 宇宙总统
  • 原文地址:https://www.cnblogs.com/HappyTeemo/p/14589198.html
Copyright © 2011-2022 走看看