前言
相比基于Linux的crontab定時任務(wù)模塊來說尝胆,在Python中使用APScheduler創(chuàng)建定時任務(wù)更加方便喉刘、精確休吠,編寫方式也更符合Python風(fēng)格吼渡,畢竟crontab里的各種**看得我心慌。且APScheduler也更適用于Django恩溅、Flask環(huán)境中添加動態(tài)任務(wù)隔箍。這篇文章就APScheduler 的使用做個簡單總結(jié)。
從一個簡單示例開始
先寫個簡單定時器示例脚乡,從代碼中理解APScheduler的使用方法:
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ProcessPoolExecutor
# 執(zhí)行器配置:使用線程池運(yùn)行定時任務(wù)蜒滩,且最大線程數(shù)為5個
executors = {
'default': ThreadPoolExecutor(max_workers=5)
}
# 配置一個調(diào)度器對象
scheduler = BackgroundScheduler(executors=executors)
# 給調(diào)度器添加定時任務(wù)task_func, 指定每日的3點(diǎn)運(yùn)行一次
scheduler .add_job(task_func, "cron", hour=3)
# 開啟定時任務(wù)
scheduler .start()
以上便是創(chuàng)建一個每日定時運(yùn)行一次的定時任務(wù)的基本方式奶稠。
配置說明
使用apscheduler配置并開啟定時任務(wù)的方法大致了解后俯艰,再去了解更多的配置項(xiàng)和對應(yīng)實(shí)現(xiàn)的功能。
- 安裝方式:
pip install apscheduler
1. 調(diào)度器Scheduler
要實(shí)現(xiàn)定時任務(wù)锌订,首先需要初始化一個調(diào)度器對象竹握,例如上例中使用的調(diào)度器為BackgroundScheduler
類,只需scheduler = BackgroundScheduler()
便創(chuàng)建出一個調(diào)度器對象辆飘。
- BackgroundScheduler類
導(dǎo)入方式:from apscheduler.schedulers.background import BackgroundScheduler
適用于在框架環(huán)境中使用啦辐,如Django、Flask中劈猪,該調(diào)度器實(shí)例在調(diào)用.start()
方法后不會發(fā)生阻塞昧甘,而是如其名一樣在后臺運(yùn)行,不影響框架中其他代碼的執(zhí)行战得。
- BlockingScheduler類
from apscheduler.schedulers.blocking import BlockingScheduler
適用于作為獨(dú)立進(jìn)程時使用充边,在自己定義的腳本程序中使用BlockingScheduler類更加方便,該調(diào)度器實(shí)例在調(diào)用.start()
方法后會阻塞常侦,等待下一個定時時間點(diǎn)的到來再繼續(xù)執(zhí)行浇冰。
2. 執(zhí)行器executors
在示例中使用的executor是線程池ThreadPoolExecutor
的方式,對應(yīng)著聋亡,當(dāng)然也可以使用進(jìn)程池ProcessPoolExecutor
的方式肘习。
其內(nèi)部調(diào)用的本身是Python內(nèi)置的concurrent.futures
模塊下的ThreadPoolExecutor及ProcessPoolExecutor類。
- ThreadPoolExecutor線程池
以多線程的方式運(yùn)行定時任務(wù)坡倔,一般情況使用該方案即可漂佩。 - ProcessPoolExecutor進(jìn)程池
以多進(jìn)程的方式運(yùn)行定時任務(wù),當(dāng)任務(wù)為CPU密集型時罪塔,應(yīng)考慮選擇該方案投蝉,當(dāng)然,該方案會更加消耗主機(jī)資源征堪。
使用方法如示例所示瘩缆,以字典方式定義執(zhí)行器,傳入最大線程或進(jìn)程數(shù)后佃蚜,在調(diào)度器實(shí)例中指定庸娱,或使用.add_executor()
添加即可着绊。
executors = {
'default': ThreadPoolExecutor(20)
}
scheduler = BackgroundScheduler(executors=executors)
# 也可使用下面的方式添加執(zhí)行器
# scheduler.add_executor()
3. 觸發(fā)器Trigger
在使用sched.add_job()
方法給調(diào)度器添加任務(wù)時,需要傳入定時啟動的方式和規(guī)定的運(yùn)行時間熟尉。
以下是add_job
方法源碼中定義可傳入的參數(shù):
def add_job(self, func, trigger=None, args=None, kwargs=None, id=None, name=None,
misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined,
next_run_time=undefined, jobstore='default', executor='default',
replace_existing=False, **trigger_args):
第一個參數(shù)func為需要定時執(zhí)行的任務(wù)函數(shù)名归露;
第三、四個參數(shù)為定時任務(wù)func的參數(shù)斤儿,如原func函數(shù)有參數(shù)靶擦,以列表或字典的形式傳入即可。
第二個trigger即為觸發(fā)器雇毫,指定執(zhí)行任務(wù)的時機(jī),常見的trigger參數(shù)有以下3個踩蔚,具體用法釋義在每個代碼注釋中包含:
- 1)date 在特定的時間日期執(zhí)行
from datetime import date
# 在2019年11月6日00:00:00執(zhí)行
scheduler.add_job(my_job1, 'date', run_date=date(2009, 11, 6))
# 在2019年11月6日16:30:05執(zhí)行棚放,兩種寫法均可
scheduler.add_job(my_job2, 'date', run_date=datetime(2009, 11, 6, 16, 30, 5))
scheduler.add_job(my_job3, 'date', run_date='2009-11-06 16:30:05')
# 立即執(zhí)行,不指定具體時間時會立即執(zhí)行任務(wù)
scheduler.add_job(my_job4, 'date')
scheduler.start()
- 2)interval 經(jīng)過指定的時間間隔執(zhí)行
from datetime import datetime
# 每兩小時執(zhí)行一次
scheduler.add_job(job_function, 'interval', hours=2)
# 在2019年10月10日09:30:00 到2020年6月15日的時間內(nèi)馅闽,每兩小時執(zhí)行一次
scheduler.add_job(job_function, 'interval', hours=2, start_date='2019-10-10 09:30:00', end_date='2020-06-15 11:00:00')
interval可使用的時間參數(shù)如下:
weeks (int) – 等待的周數(shù)
days (int) – 等待的天數(shù)
hours (int) – 等待的小時數(shù)
minutes (int) – 等待的分鐘數(shù)
seconds (int) – 等待的秒數(shù)
start_date (datetime|str) – 區(qū)間計(jì)算的起點(diǎn)時間
end_date (datetime|str) – 區(qū)間計(jì)算的終止時間
timezone (datetime.tzinfo|str) – 用于日期/時間計(jì)算的時區(qū)
- 3)cron按指定的周期執(zhí)行
在最初的示例中使用的便是該類觸發(fā)器飘蚯,按指定的周期循環(huán)運(yùn)行。
# 在每天的3:00點(diǎn)運(yùn)行
scheduler.add_job(task_func, "cron", hour=3)
# 在每個6福也、7局骤、8、11暴凑、12月的第三個周五的00:00, 01:00, 02:00和03:00 執(zhí)行
scheduler.add_job(job_function, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3')
# 在2019年5月30日前的周一到周五的5:30執(zhí)行
scheduler.add_job(job_function, 'cron', day_of_week='mon-fri', hour=5, minute=30, end_date='2019-05-30')
cron可使用的時間參數(shù)如下:
year (int|str) – 年(4位數(shù)的年份)
month (int|str) – 月(1-12)
day (int|str) – 日 (1-31)
week (int|str) – ISO周日歷 (1-53)
day_of_week (int|str) – 英文簡寫或數(shù)字表示的星期幾 (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 (datetime|str) – 最早可能觸發(fā)的日期/時間(包括在內(nèi))
end_date (datetime|str) – 最晚可能觸發(fā)的日期/時間(包括在內(nèi))
timezone (datetime.tzinfo|str) – 用于日期/時間計(jì)算的時區(qū) (默認(rèn)為調(diào)度程序的時區(qū))
觸發(fā)器的參數(shù)看起來內(nèi)容太多峦甩,但其實(shí)都不用記住,只需在明確需求后去上述參數(shù)中查找现喳,組合并設(shè)置自己想指定的定時方案即可凯傲。
4. 任務(wù)儲存器
除以上3個核心功能外,定時任務(wù)還可以指定持久儲存方案嗦篱。
默認(rèn)的儲存器使用的是使用內(nèi)存冰单,當(dāng)任務(wù)意外中斷,重啟后定義的任務(wù)也會重新被添加到調(diào)度器灸促,簡單而高效诫欠;
但當(dāng)作業(yè)中斷需要從中斷中恢復(fù)任務(wù),則在配置時應(yīng)該使用數(shù)據(jù)庫來作為任務(wù)儲存器浴栽,具體使用什么數(shù)據(jù)庫荒叼,可以自行選擇SQLite、MongoDB吃度、Redis甩挫。
定義方法如下,這里不做過多介紹椿每,如需使用伊者,再查找相關(guān)文檔:
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
jobstores = {
'mongo': {'type': 'mongodb'},
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
scheduler = BackgroundScheduler(executors=executors英遭, jobstores=jobstores)
以上。
最后亦渗,如果需要創(chuàng)建的定時任務(wù)太多挖诸,應(yīng)該了解學(xué)習(xí)下RabbitMQ異步隊(duì)列的使用。