使用APScheduler開啟定時任務(wù)

前言

相比基于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ì)列的使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末法精,一起剝皮案震驚了整個濱河市多律,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搂蜓,老刑警劉巖狼荞,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帮碰,居然都是意外死亡相味,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門殉挽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丰涉,“玉大人,你說我怎么就攤上這事斯碌∫凰溃” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵傻唾,是天一觀的道長投慈。 經(jīng)常有香客問我,道長冠骄,這世上最難降的妖魔是什么逛裤? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮猴抹,結(jié)果婚禮上带族,老公的妹妹穿的比我還像新娘。我一直安慰自己蟀给,他們只是感情好蝙砌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跋理,像睡著了一般择克。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上前普,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天肚邢,我揣著相機(jī)與錄音,去河邊找鬼。 笑死骡湖,一個胖子當(dāng)著我的面吹牛贱纠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播响蕴,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谆焊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浦夷?” 一聲冷哼從身側(cè)響起辖试,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劈狐,沒想到半個月后罐孝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肥缔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年肾档,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辫继。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俗慈,靈堂內(nèi)的尸體忽然破棺而出姑宽,到底是詐尸還是另有隱情,我是刑警寧澤闺阱,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布炮车,位于F島的核電站,受9級特大地震影響酣溃,放射性物質(zhì)發(fā)生泄漏瘦穆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一赊豌、第九天 我趴在偏房一處隱蔽的房頂上張望扛或。 院中可真熱鬧,春花似錦碘饼、人聲如沸熙兔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽住涉。三九已至,卻和暖如春钠绍,著一層夾襖步出監(jiān)牢的瞬間舆声,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工柳爽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留媳握,地道東北人碱屁。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像毙芜,于是被迫代替她去往敵國和親忽媒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一點(diǎn)知識 在JAVA開發(fā)領(lǐng)域腋粥,目前可以通過以下幾種方式進(jìn)行定時任務(wù): Timer:jdk中自帶的一個定時調(diào)度類晦雨,可...
    雅倩蘭爸爸閱讀 3,839評論 1 28
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,097評論 1 32
  • 高階函數(shù):將函數(shù)作為參數(shù) sortted()它還可以接收一個key函數(shù)來實(shí)現(xiàn)自定義的排序,reversec參數(shù)可反...
    royal_47a2閱讀 686評論 0 0
  • 7月14日 現(xiàn)在的狀態(tài)用迷茫二字最為貼切, 現(xiàn)在的我每天誠惶誠恐的工作隘冲、生活闹瞧。 上班每天小心翼翼,生怕出現(xiàn)一點(diǎn)問題...
    度浩閱讀 230評論 2 1
  • 郁江大橋 1976年展辞,郁江河上迎來了第一座大橋奥邮,時隔41年,這座橋經(jīng)歷了諸多磨難罗珍,破敗不堪洽腺,已經(jīng)不能承受車子的碾壓...
    種豆南下閱讀 257評論 0 0