Skip to main content

1、定时任务的设计和思路

Y-aong...About 8 min模块设计定时任务定时任务

1、定时任务的设计和思路

一、Python中定时任务模块

1. Celery

Celery 是一个分布式任务队列,它不仅支持简单的任务调度,还可以处理复杂的任务工作流。对于已经使用了Celery的项目来说,可以很方便地添加定时任务功能。然而,对于不需要分布式处理能力的小型应用或项目来说,可能显得过于重量级。

  • 优点:支持大规模的任务调度,拥有良好的社区支持。
  • 缺点:配置相对复杂,需要额外的消息中间件(如RabbitMQ, Redis)来协调任务分发。

2. APScheduler (Advanced Python Scheduler)

APScheduler 是一个灵活且强大的Python库,允许开发者轻松地创建和管理各种类型的定时任务。它可以很好地集成到现有的Web应用程序中,并提供了多种调度方式,包括固定间隔、定时执行等。

  • 优点:易于使用,支持持久化存储,能够动态添加/移除任务。

  • 缺点:对于非常简单的场景来说,可能会有些“大材小用”。

3、Celery vs APScheduler 对比表

特性CeleryAPScheduler
主要用途分布式任务队列,用于处理大量消息,同时也支持定时任务。专注于定时任务调度,提供灵活的任务管理和持久化选项。
安装复杂度需要额外配置消息中间件(如RabbitMQ, Redis),并且有较多的配置项。相对简单,直接通过pip安装即可使用,无需依赖外部服务。
任务调度类型支持基于时间间隔、固定时间点以及cron表达式的调度方式。支持基于日期、固定时间间隔以及cron类型的调度,并且可以实现持久化任务。
动态添加/移除任务原生不支持动态添加或删除任务,可以通过第三方插件实现。支持在运行时动态添加和移除任务,同时允许修改现有任务的属性。
持久化支持不具备内置的任务持久化功能,依赖于所选的消息中间件。内置多种持久化方案,包括内存、MongoDB、SQLAlchemy等。
并发执行支持多线程、多进程以及事件驱动模型下的任务并行执行。提供了不同类型的执行器来满足不同的并发需求,如线程池、进程池等。
集成能力可以与Django、Flask等多种Web框架良好集成,并且能够与其他编程语言通信。易于与各种Python框架集成,例如Flask、Tornado等,并提供了异步支持。
社区支持拥有一个庞大而活跃的社区,文档详尽,遇到问题容易找到解决方案。社区相对较小,但官方文档质量较高,用户反馈积极。
适用场景适用于大型项目中需要高性能、高可用性的分布式任务处理场景。更适合中小型项目中的定时任务需求,特别是当不需要复杂的分布式架构时。

从上表可以看出,Celery 和 APScheduler 在设计目标上有明显的差异:前者更侧重于构建一个强大的分布式任务处理系统,后者则专注于为开发者提供一个轻量级且易于使用的定时任务调度工具。因此,在选择合适的库之前,应该根据项目的具体需求进行权衡。对于只需要定时任务而不涉及复杂的消息传递或大规模任务分发的应用来说,APScheduler 是一个非常好的选择;而对于那些已经存在或者预计未来会扩展到包含分布式计算元素的应用,则可能更适合采用 Celery .

二、定时任务的实现原理

1. 小顶堆算法

在某些情况下,我们可以利用小顶堆(Min Heap)来组织待执行的任务列表。每个任务都有一个预定的执行时间戳作为键值存入堆中;当系统时间到达某个任务的时间戳时,该任务就会被取出并执行。这种方法适用于那些对任务执行顺序有严格要求的应用场景。

每个节点是对应的定时任务,定时任务的执行顺序通过利用堆化进行排序,循环判断每秒是否堆顶的任务是否应该执行,每次插入任务、删除任务需要重新堆化;

img

2. 时间轮算法

时间轮是一种高效的任务调度机制,特别适合处理大量短周期性任务。它将所有任务按照它们预计被执行的时间分散到不同的“槽位”上,然后通过一个不断前进的指针来触发相应槽位内到期的任务。相比于传统的线性搜索方法,时间轮可以在常数时间内完成新任务的插入以及旧任务的触发。

round 时间轮: 时间轮其实就是一种环型的数据结构,可以把它想象成一个时钟,分成了许多格子,每个格子代表一定的时间,在这个格子上用一个链表来保存要执行的超时任务,同时有一个指针一格一格的走,走到那个格子时就执行格子对应的延迟任务。

img

3. 分层时间轮

为了克服单层时间轮所能支持的最大超时时间有限的问题,可以通过构建多层级的时间轮来扩展其适用范围。例如,在最底层的时间轮里设置较短的基本时间单位(tick),而在更高层次则采用更大的tick值。这样既可以保持较高的精度,又不会因为过长的等待时间而浪费过多资源。

就是将月、周、天分成不同的时间轮层级,各自的时间轮进行定义:

img
img

4. 无限循环

这是一种最基础也是最直接的方式,即在一个while循环体内持续检查当前时间和预设的执行时间是否匹配,如果匹配就调用相应的函数。虽然简单易懂,但这种方式会占用一定的CPU资源,并且难以做到精准控制。

三、定时任务的类型

根据任务的不同需求,我们可以将其分为以下几类:

  • 指定时间点运行:这类任务会在特定日期和时间启动一次,类似于cron表达式中的@midnight或者0 0 * * *这样的规则。

  • 间隔执行:按照一定的时间间隔重复执行,比如每隔几分钟或几小时执行一次。

  • 定时执行:基于cron表达式的定义,可以在每天、每周甚至每月的固定时间点自动触发。

四、定时任务设计的注意点

1. 定时总开关——假期等时间点如何停止所有的定时任务

为了应对特殊情况(如法定节假日),我们应该考虑为整个系统提供一个总的启停按钮。这个按钮可以是一个环境变量或者是数据库表中的字段,用来指示当前是否允许任何定时任务运行。此外,也可以针对不同类型的定时任务单独设置开关,以便更加精细地控制哪些任务应该暂停。

2. 定时确认——有的定时任务是不是需要人工干预

对于一些关键性的操作,可能需要加入人工审核步骤,确保只有经过授权之后才能继续执行。这可以通过发送邮件、短信或者其他即时通讯工具通知相关人员来进行审批。一旦获得批准,再由后台程序正式执行任务。

3. 结果通知——定时任务完成后的消息通知

一旦定时任务顺利完成,应当及时向相关方通报结果。这可以通过电子邮件、企业微信等方式实现。同时,还可以附带日志链接或其他有用信息,方便后续查询和审计。

4. 可用时间/不可用时间——定时执行是否处于可用时间

考虑到业务逻辑的实际需求,某些定时任务只应在特定的工作时间内执行,而非全天候无休止地运行。因此,我们需要定义一套规则来限制这些任务只能在规定的时间段内生效。

5. 日志记录——定时任务真的执行了吗

每次定时任务执行前后都应生成详细的日志条目,记录下开始时间、结束时间、状态变更等重要信息。这样做不仅可以帮助我们追踪问题所在,也为未来的优化提供了宝贵的参考资料。

综上所述,设计一个健壮且高效的定时任务系统需要综合考虑多个方面的要求和技术细节。从选择合适的调度引擎到制定合理的执行策略,再到确保良好的用户体验,每一个环节都需要精心规划与实施。希望上述内容能为您提供有价值的指导。

Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.15.8