之前一直使用schedule
定时任务,而随着业务的不断变化,我发现在业务中schedule
在满足业务上有一些吃力,一部分是我用的异步代码较多,而且时间要求上很灵活。用achedule
多了,管理较为困难。这时就发现了一个更加灵活的库APScheduler
其实严格意义上来说已经是一个完整的框架了。在某些场景下,比celery
好用(我说的)。
安装
pip install apscheduler
使用
先看一个最简单的案例,每5秒执行函数一次
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import asyncio
import os
import datetime
async def run():
print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]执行一次")
if __name__ == '__main__':
executor = AsyncIOScheduler(
timezone='Asia/Shanghai',
job_defaults={
"misfire_grace_time": 3600, # 允许存在多久时间的任务数
"max_instances": 200, # 该定时任务允许最大的实例个数
"coalesce": False # 多个任务堆积,是否运行最新的
}
)
executor.add_job(
run,
trigger='interval',
seconds=5,
coalesce=False,
misfire_grace_time=3600,
args=[])
executor.start()
print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]线程开始执行")
try:
asyncio.get_event_loop().run_forever()
except (KeyboardInterrupt, SystemExit):
pass
虽然对于第一次接触的同学看着可能不是很明白,但是其实还是很简单的。整体分为3部分。
executor = AsyncIOScheduler()
创建异步任务executor.add_job()、executor.start()
添加任务/启动任务asyncio.get_event_loop().run_forever()
写入循环任务开始
这里有一个问题要先说一下,就是因为apscheduler
是一个功能强大且完善的定时任务框架,而且涉及了5大部分,分别是触发器(trigger)、作业存储(job store)、执行器(executor)、调度器(scheduler)、任务或作业(task)。
我目前也并没有一个项目是完整用到5个模块的。所以我主要还是说我用到的地方,别的地方我会先写上,以后我用到的话,会回来在补充上。
触发器(tigger)
这部分比较简单,APScheduler
有三种自带的tigger
,基本满足各种刁钻的业务要求了。
- interval: 固定时间间隔触发
- date: 特定的时间点触发(作业只会执行一次
- cron: 在特定时间周期性地触发(量化常用)
executor.add_job(
run,
trigger='interval',
seconds=5,
)
executor.add_job(
run,
trigger='corn',
minute='*/5',
)
executor.add_job(
run,
trigger='cron',
year="*", month="*", day="*", hour="15", minute="07", second="00"
)
执行器(executor)
BlockingScheduler
阻塞式调度器,适用于只跑调度器的程序BackgroundScheduler
后台式调度器,适用于非阻塞的情况,调度器会在后台运行AsyncIOScheduler
我目前比较常用的,可以适用于async
任务TornadoScheduler
Tornado调度器,还没用过TwistedScheduler
Twisted调度器,还没用过QtScheduler
Qt调度器,还没用过
调度器(scheduler)
我在业务中暂时还没有用到,引用网上的说明,有机会尝试后我会在来完善
配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。 调度器主要用到阻塞和后台运行这2种 BlockingScheduler:main_loop就在当前进程的主线程内运行,所以调用start函数后会阻塞当前线程。通过一个threading.Event条件变量对象完成scheduler的定时唤醒。 BackgroundScheduler:和BlockingScheduler基本一样,除了main_loop放在了单独线程里,所以调用start后主线程不会阻塞
任务或作业(task)
目前只是用到add_job
添加任务,其余的暂时还没用过。
补充
cron
触发器的参数如下
# 参数 类型 说明
year (int|str) 年,4位数字
month (int|str) 月,范围1-12
day (int|str) 日,范围1-31
week (int|str) 周,范围1-53
day_of_week (int|str) 周内第几天或星期几,范围0-6或mon,tue,wed,thu,fri,sat,sun
hour (int|str) 时,范围0~23
minute (int|str) 分,范围0-59
second (int|str) 秒,范围0-59
start_date (datime|str) 最早开始日期(包含)
end_date (datetime|str) 最晚结束日期(包含)
timezone (datetime.tzinfo|str) 指定时区
interval
触发器的参数如下
# 参数 类型 说明
weeks int 间隔几周
days int 间隔几天
houres int 间隔几小时
minutes int 间隔几分钟
seconds int 间隔几秒钟
start_date datetime/str 开始日期
end_time datetime/str 结束日期
timezone dateime.tzinfo/str 时区