文章目录
前言
常见定时任务:
Crontab:只能在linux环境下使用
Schedule:适合比较轻量级的一些调度任务,复杂场景下难以应用
APScheduler:提供了非常丰富而且方便易用的定时任务接口,灵活强大,还支持持久化存储。
Celery:很强,但本人应用于物联网设备端,硬件资源有限且该技术依赖较多
APScheduler优势:使用起来十分方便。提供了基于日期、固定时间间隔以及crontab 类型的任务,我们可以在主程序的运行过程中快速增加新作业或删除旧作业,如果需要持久化存储,可以把作业存储在数据库中,作业的状态会被保存,当调度器重启时,不必重新添加作业,作业会恢复原状态继续执行。
一、安装
pip install apscheduler
二、简单使用
1.代码如下(示例)
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
def my_clock():
print(f"Hello! The time is:{
datetime.now()}")
if __name__ == '__main__':
scheduler = BlockingScheduler()
scheduler.add_job(my_clock, "interval", seconds=3)
scheduler.start()
说明:
本文章都基于:APSchedule(3.7.0)版本
- 第1行:导入调度器模块 BlockingScheduler,这是最简单的调度器,调用 start
方阻塞当前进程。(注:此为APScheduler四组件之schedulers (调度器))。 - 第2行:导入时间日期模块
- 第4-5行:定义my_clock函数,功能为打印出当前时间
- 第7行,为程序主入口
- 第8行:实例化一个 BlockingScheduler类,不带参数表明使用默认的作业存储器-内存(注:此为APScheduler四组件之jobstores (job存储)),默认的执行器是线程池执行器(注:此为APScheduler四组件之executors (执行器)),最大并发线程数默认为 10个(另一个是进程池执行器)
- 第9行: 将my_clock添加到任务调度中。然后看interval参数(注:此为APScheduler四组件之triggers(触发器)),这里用的是间隔的方式来调度,调度频率是seconds=3,也就是每3秒执行一次。
- 第10行:APScheduler 定时任务启动执行
2.APScheduler 的运行流程
1、设定调度器用以对任务的调度与安排进行全局统筹
2、对相应的函数或方法上设定相应的触发器,并添加到调度器中
3、如有任务持久化需要则需要设定对应的持久化层,否则默认使用内存存储任务
4、当触发器被触发时,就将任务交由执行器进行执行
三、APScheduler 四组件
上面的示例中已经引入APScheduler 四组件的概念,我们需要了解这四种组件的概念和用法,才能全局掌握APScheduler 定时任务框架。
1.调度器(schedulers)—不同程序引用
任务调度器是属于整个调度的总指挥官。他会合理安排作业存储器、执行器、触发器进行工作,并进行添加和删除任务等。应用程序开发人员通常不会直接处理作业存储库,执行程序或触发器。相反,调度程序提供了适当的接口来处理所有这些接口。配置作业存储和执行程序是通过计划程序完成的,添加,修改和删除作业也是如此
调度程序的选择主要取决于您的编程环境以及APScheduler的用途。
- BlockingScheduler:当调度程序是您的流程中唯一运行的东西时使用
from apscheduler.schedulers.background import BlockingScheduler
- BackgroundScheduler:在不使用以下任何框架且希望调度程序在应用程序内部的后台运行时使用
from apscheduler.schedulers.background import BackgroundScheduler
- AsyncIOScheduler:如果您的应用程序使用asyncio模块,则使用
from apscheduler.schedulers.asyncio import AsyncIOScheduler
- GeventScheduler:如果您的应用程序使用gevent,则使用
from apscheduler.schedulers.gevent import GeventScheduler
- TornadoScheduler:在构建Tornado应用程序时使用 TwistedScheduler:在构建Twisted应用程序时使用
from apscheduler.schedulers.tornado import TornadoScheduler
- QtScheduler:在构建Qt应用程序时使用
from apscheduler.schedulers.qt import QtScheduler
2.任务存储器(job stores)—持久化存储
- 1.默认的任务存储器为内存,不需要配置和管理。如下:
from apscheduler.schedulers.blocking import BackgroundScheduler
scheduler = BackgroundScheduler()
此为选择BackgroundScheduler调度器,不会阻塞程序,使用内存任务存储器。
缺点:非持久化存储,如果调度器重启或应用程序崩溃时,原有的任务就会丢失。
- 2.使用数据库作为任务存储器,持久化存储。调度器重启或应用程序崩溃时,作业可以从中断时恢复正常运行,重新恢复有些作业可能错过时间,可以进行对应设置,比如
misfire_grace_time
即作业运行的时间和当下时间的差值,在差值内可继续运行。- SQLAlchemy形式的数据库,这里就主要是指各种传统的关系型数据库,如MySQL、PostgreSQL、SQLite 等。
- mongodb 非结构化的 Mongodb 数据库,该类型数据库经常用于对非结构化或版结构化数据的存储或操作,如 JSON。
- redis 内存数据库,通常用作数据缓存来使用,当然通过一些主从复制等方式也能实现当中数据的持久化或保存。
例:jobstores指定任务存储器为sqlite数据库,进行持久化存储。
需要安装sqlalchemy库
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
jobstores = {
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
scheduler = BackgroundScheduler(jobstores=jobstores)
3.任务触发器(triggers)—不同定时模式
APScheduler 任务触发器提供了三种不同的定时模式:
- date:日期触发器。主要是指定时在某一日期时间点进行任务触发,通常适用于一次性任务火作业调度。
from apscheduler.schedulers.blocking import BlockingScheduler
import datetime
def my_clock():
print(f"Hello! The time is:{
datetime.datetime.now()}")
if __name__ == '__main__':
scheduler = BlockingScheduler()
scheduler.add_job(
my_clock,
trigger='date',
run_date=datetime.datetime(2021, 5, 15, 10, 30, 00),
# run_date='2021-05-15 10:30:00'
)
scheduler.start()
上例为trigger指定为date的任务,代表2021年5月15日10时30分00秒运行。
支持如果想立即运行 job ,则可以在添加 job 时省略 trigger 参数;
添加 job 时的日期设置参数支持:
字符串格式('2019-12-31' 或者 '2019-12-31 12:01:30')、datetime.date(datetime.date(2019, 12, 31)) 或者 datetime.datetime(datetime.datetime(2019, 12, 31, 16, 30, 1))
2.interval:间隔触发器。按照时、分、秒、天、周这几个部分进行周期性重复任务。
主要参数:
- start_date(date|datetime|str) - 开始时间,eg:‘2021-01-01 00:00:00’
- end_date(date|datetime|str) - 结束时间,eg:‘2021-12-01 00:00:00’ 当天就要结束
- weeks(int) - 表示等待时间的周数
- days(int) - 表示等待时间天数
- hours(int) - 表示等待时间小时数
- minutes(int) - 表示等待时间分钟数
- seconds(int) - 表示等待时间秒数
from apscheduler.schedulers.blocking import BlockingScheduler
import datetime
def my_clock():
print