APScheduler
最近想写个任务调度程序,于是研究了下 Python 中的任务调度工具,比较有名的是:Celery,RQ,APScheduler。
Celery:非常强大的分布式任务调度框架
RQ:基于Redis的作业队列工具
APScheduler:一款强大的任务调度工具
RQ 参考 Celery,据说要比 Celery 轻量级。在我看来 Celery 和 RQ 太重量级了,需要单独启动进程,并且依赖第三方数据库或者缓存,适合嵌入到较大型的 python 项目中。其次是 Celery 和 RQ 目前的最新版本都不支持动态的添加定时任务(celery 官方不支持,可以使用第三方的 redisbeat 或者 redbeat 实现),所以对于一般的项目推荐用 APScheduler,简单高效。
Apscheduler是一个基于Quartz的python定时任务框架,相关的 api 接口调用起来比较方便,目前其提供了基于日期、固定时间间隔以及corntab类型的任务,并且可持久化任务;同时它提供了多种不同的调用器,方便开发者根据自己的需求进行使用,也方便与数据库等第三方的外部持久化储存机制进行协同工作,非常强大。
安装
最简单的方法是使用 pip 安装:
$ pip install apscheduler
$ python setup.py install
目前版本:3.6.3
基本概念
APScheduler 具有四种组件:
triggers(触发器)
jobstores (job 存储)
executors (执行器)
schedulers (调度器)
triggers:触发器管理着 job 的调度方式。
jobstores: 用于 job 数据的持久化。默认 job 存储在内存中,还可以存储在各种数据库中。除了内存方式不需要序列化之外(一个例外是使用 ProcessPoolExecutor),其余都需要 job 函数参数可序列化。另外多个调度器之间绝对不能共享 job 存储(APScheduler 原作者的意思是不支持分布式,但是我们可以通过重写部分函数实现,具体方法后面再介绍)。
executors:负责处理 job。通常使用线程池(默认)或者进程池来运行 job。当 job 完成时,会通知调度器并发出合适的事件。
schedulers: 将 job 与以上组件绑定在一起。通常在程序中仅运行一个调度器,并且不直接处理 jobstores ,executors 或 triggers,而是通过调度器提供的接口,比如添加,修改和删除 job。
选择正确的调度器,job 存储,执行器和触发器
调度器的选择主要取决于编程环境以及 APScheduler 的用途。主要有以下几种跳度器:
apscheduler.schedulers.blocking.BlockingScheduler:当调度器是程序中唯一运行的东西时使用,阻塞式。
apscheduler.schedulers.background.BackgroundScheduler:当调度器需要后台运行时使用。
apscheduler.schedulers.asyncio.AsyncIOScheduler:当程序使用 asyncio 框架时使用。
apscheduler.schedulers.gevent.GeventScheduler:当程序使用 gevent 框架时使用。
apscheduler.schedulers.tornado.TornadoScheduler:当构建 Tornado 程序时使用
apscheduler.schedulers.twisted.TwistedScheduler:当构建 Twisted 程序时使用
apscheduler.schedulers.qt.QtScheduler:当构建 Qt 程序时使用
要选择适当的 job 存储,需要看 job 是否需要持久化。如果程序启动会重新创建作业,则可以使用默认的内存方式(MemoryJobStore)。如果需要 job 在程序重新启动或崩溃后继续存在,那么建议使用其他 job 存储方式。系统内置主要有以下几种 job 存储:
apscheduler.jobstores.memory.MemoryJobStore:使用内存存储
apscheduler.jobstores.mongodb.MongoDBJobStore:使用 MongoDB 存储
apscheduler.jobstores.redis.RedisJobStore:使用 redis 存储
apscheduler.jobstores.rethinkdb.RethinkDBJobStore:使用 rethinkdb 存储
apscheduler.jobstores.sqlalchemy.SQLAlchemyJobStore:使用 ORM 框架 SQLAlchemy,后端可以是 sqlite、mysql、PoatgreSQL 等数据库
apscheduler.jobstores.zookeeper.ZooKeeperJobStore:使用 zookeeper 存储
执行器的选择要根据 job 的类型。默认的线程池执行器 apscheduler.executors.pool.ThreadPoolExecutor 可以满足大多数情况。如果 job 属于 CPU 密集型操作则建议使用进程池执行器 apscheduler.executors.pool.ProcessPoolExecutor。当然也可以同时使用两者,将进程池执行器添加为辅助执行器。
当添加 job 时,可以选择一个触发器,它管理着 job 的调度方式。APScheduler 内置三种触发器:
apscheduler.triggers.date:在某个特定时间仅运行一次 job 时使用
apscheduler.triggers.interval:当以固定的时间间隔运行 job 时使用
apscheduler.triggers.cron:当在特定时间定期运行 job 时使用
配置调度器
APScheduler 提供了多种不同的方式来配置调度器。
假设使用默认 job 存储和默认执行器运行 BackgroundScheduler:
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
以上创建了一个 BackgroundScheduler 调度器,job 存储使用默认的 MemoryJobStore,执行器使用默认的 ThreadPoolExecutor,最大线程数 10 个。
假如想做以下设置:
一个名为 mongo 的 job 存储,后端使用 MongoDB
一个名为 default 的 job 存储,后端使用数据库(使用 Sqlite)
一个名为 default 的线程池执行器,最大线程数 20 个
一个名为 processpool 的进程池执行器,最大进程数 5 个
调度器使用 UTC 时区
开启 job 合并
job 最大实例限制为 3 个
方法一:
from pytz import utc
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.mongodb import MongoDBJobStore
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
jobstores = {
'mongo': MongoDBJobStore(),
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
executors = {
'default': ThreadPoolExecutor(20),
'processpool': ProcessPoolExecutor(5)
}
job_defaults = {
'coalesce': False,
'max_instances': 3
}
scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
方法二:
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler({
'apscheduler.jobstores.mongo': {
'type': 'mongodb'
},
'apscheduler.jobstores.default': {
'type': 'sqlalchemy',
'url': 'sqlite:///job