APScheduler初探

APScheduler最基本的用法: “定時(shí)幾秒后啟動(dòng)job”
兩種調(diào)度器: BackgroundScheduler和BlockingScheduler的區(qū)別,
job執(zhí)行時(shí)間大于定時(shí)調(diào)度時(shí)間特殊情況的問題及解決方法
每個(gè)job都會(huì)以thread的方式被調(diào)度约素。

1幸乒、基本的定時(shí)調(diào)度

APScheduler是python的一個(gè)定時(shí)任務(wù)調(diào)度框架睹逃,能實(shí)現(xiàn)類似linux下crontab類型的任務(wù)机隙,使用起來比較方便智玻。它提供基于固定時(shí)間間隔桐绒、日期以及crontab配置類似的任務(wù)調(diào)度夺脾,并可以持久化任務(wù),或?qū)⑷蝿?wù)以daemon方式運(yùn)行茉继。

下面是一個(gè)最基本的使用示例:

from apscheduler.schedulers.blocking import BlockingScheduler

def job():
    print('job 3s')

if __name__=='__main__':
    sched = BlockingScheduler(timezone='MST')
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

它能實(shí)現(xiàn)每隔3s就調(diào)度job()運(yùn)行一次咧叭,所以程序每隔3s就輸出’job 3s’。通過修改add_job()的參數(shù)seconds烁竭,就可以改變?nèi)蝿?wù)調(diào)度的間隔時(shí)間菲茬。

2、BlockingScheduler與BackgroundScheduler區(qū)別

APScheduler中有很多種不同類型的調(diào)度器,BlockingScheduler與BackgroundScheduler是其中最常用的兩種調(diào)度器生均。那他們之間有什么區(qū)別呢听想? 簡(jiǎn)單來說,區(qū)別主要在于BlockingScheduler會(huì)阻塞主線程的運(yùn)行马胧,而BackgroundScheduler不會(huì)阻塞汉买。所以,我們?cè)诓煌那闆r下佩脊,選擇不同的調(diào)度器:

BlockingScheduler: 調(diào)用start函數(shù)后會(huì)阻塞當(dāng)前線程蛙粘。當(dāng)調(diào)度器是你應(yīng)用中唯一要運(yùn)行的東西時(shí)(如上例)使用。
BackgroundScheduler: 調(diào)用start后主線程不會(huì)阻塞威彰。當(dāng)你不運(yùn)行任何其他框架時(shí)使用出牧,并希望調(diào)度器在你應(yīng)用的后臺(tái)執(zhí)行。
下面用兩個(gè)例子來更直觀的說明兩者的區(qū)別歇盼。

BlockingScheduler例子

from apscheduler.schedulers.blocking import BlockingScheduler
import time

def job():
    print('job 3s')


if __name__=='__main__':

    sched = BlockingScheduler(timezone='MST')
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True): # 不會(huì)被執(zhí)行到
        print('main 1s')
        time.sleep(1)

運(yùn)行這個(gè)程序舔痕,我們得到如下的輸出:

job 3s
job 3s
job 3s
job 3s

可見,BlockingScheduler調(diào)用start函數(shù)后會(huì)阻塞當(dāng)前線程豹缀,導(dǎo)致主程序中while循環(huán)不會(huì)被執(zhí)行到伯复。

BackgroundScheduler例子

from apscheduler.schedulers.background import BackgroundScheduler
import time

def job():
    print('job 3s')


if __name__=='__main__':

    sched = BackgroundScheduler(timezone='MST')
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True):
        print('main 1s')
        time.sleep(1)

可見,BackgroundScheduler調(diào)用start函數(shù)后并不會(huì)阻塞當(dāng)前線程邢笙,所以可以繼續(xù)執(zhí)行主程序中while循環(huán)的邏輯啸如。

main 1s
main 1s
main 1s
job 3s
main 1s
main 1s
main 1s
job 3s

通過這個(gè)輸出,我們也可以發(fā)現(xiàn)氮惯,調(diào)用start函數(shù)后叮雳,job()并不會(huì)立即開始執(zhí)行。而是等待3s后妇汗,才會(huì)被調(diào)度執(zhí)行帘不。

如何讓job在start()后就開始運(yùn)行
如何才能讓調(diào)度器調(diào)用start函數(shù)后,job()就立即開始執(zhí)行呢杨箭?

其實(shí)APScheduler并沒有提供很好的方法來解決這個(gè)問題厌均,但有一種最簡(jiǎn)單的方式,就是在調(diào)度器start之前告唆,就運(yùn)行一次job()棺弊,如下

from apscheduler.schedulers.background import BackgroundScheduler
import time

def job():
    print('job 3s')


if __name__=='__main__':
    job() # 執(zhí)行一次就好了喲
    sched = BackgroundScheduler(timezone='MST')
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True):
        print('main 1s')
        time.sleep(1)

這樣就能得到如下的輸出

job 3s
main 1s
main 1s
main 1s
job 3s
main 1s
main 1s
main 1s

這樣雖然沒有絕對(duì)做到“讓job在start()后就開始運(yùn)行”,但也能做到“不等待調(diào)度擒悬,而是剛開始就運(yùn)行job”模她。

如果job執(zhí)行時(shí)間過長(zhǎng)會(huì)怎么樣
如果執(zhí)行job()的時(shí)間需要5s,但調(diào)度器配置為每隔3s就調(diào)用一下job()懂牧,會(huì)發(fā)生什么情況呢侈净?我們寫了如下例子:

from apscheduler.schedulers.background import BackgroundScheduler
import time

def job():
    print('job 3s')
    time.sleep(5)

if __name__=='__main__':

    sched = BackgroundScheduler(timezone='MST')
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True):
        print('main 1s')
        time.sleep(1)

運(yùn)行這個(gè)程序尊勿,我們得到如下的輸出:

main 1s
main 1s
main 1s
job 3s
main 1s
main 1s
main 1s
Execution of job "job (trigger: interval[0:00:03], next run at: 2018-05-07 02:44:29 MST)" skipped: maximum number of running instances reached (1)
main 1s
main 1s
main 1s
job 3s
main 1s

可見,3s時(shí)間到達(dá)后畜侦,并不會(huì)“重新啟動(dòng)一個(gè)job線程”元扔,而是會(huì)跳過該次調(diào)度,等到下一個(gè)周期(再等待3s)旋膳,又重新調(diào)度job()澎语。

為了能讓多個(gè)job()同時(shí)運(yùn)行,我們也可以配置調(diào)度器的參數(shù)max_instances验懊,如下例擅羞,我們?cè)试S2個(gè)job()同時(shí)運(yùn)行:

from apscheduler.schedulers.background import BackgroundScheduler
import time

def job():
    print('job 3s')
    time.sleep(5)

if __name__=='__main__':
    job_defaults = { 'max_instances': 2 }
    sched = BackgroundScheduler(timezone='MST', job_defaults=job_defaults)
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True):
        print('main 1s')
        time.sleep(1)

運(yùn)行程序,我們得到如下的輸出:

main 1s
main 1s
main 1s
job 3s
main 1s
main 1s
main 1s
job 3s
main 1s
main 1s
main 1s
job 3s

每個(gè)job是怎么被調(diào)度的
通過上面的例子义图,我們發(fā)現(xiàn)减俏,調(diào)度器是定時(shí)調(diào)度job()函數(shù),來實(shí)現(xiàn)調(diào)度的碱工。

那job()函數(shù)會(huì)被以進(jìn)程的方式調(diào)度運(yùn)行娃承,還是以線程來運(yùn)行呢?

為了弄清這個(gè)問題怕篷,我們寫了如下程序:

from apscheduler.schedulers.background import BackgroundScheduler
import time,os,threading

def job():
    print('job thread_id-{0}, process_id-{1}'.format(threading.get_ident(), os.getpid()))
    time.sleep(50)

if __name__=='__main__':
    job_defaults = { 'max_instances': 20 }
    sched = BackgroundScheduler(timezone='MST', job_defaults=job_defaults)
    sched.add_job(job, 'interval', id='3_second_job', seconds=3)
    sched.start()

    while(True):
        print('main 1s')
        time.sleep(1)

運(yùn)行程序草慧,我們得到如下的輸出:

main 1s
main 1s
main 1s
job thread_id-10644, process_id-8872
main 1s
main 1s
main 1s
job thread_id-3024, process_id-8872
main 1s
main 1s
main 1s
job thread_id-6728, process_id-8872
main 1s
main 1s
main 1s
job thread_id-11716, process_id-8872

可見,每個(gè)job()的進(jìn)程ID都相同匙头,但線程ID不同。所以仔雷,job()最終是以線程的方式被調(diào)度執(zhí)行蹂析。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碟婆,隨后出現(xiàn)的幾起案子电抚,更是在濱河造成了極大的恐慌,老刑警劉巖竖共,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝙叛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡公给,警方通過查閱死者的電腦和手機(jī)借帘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淌铐,“玉大人肺然,你說我怎么就攤上這事⊥茸迹” “怎么了际起?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我街望,道長(zhǎng)校翔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任灾前,我火速辦了婚禮防症,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豫柬。我一直安慰自己告希,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布烧给。 她就那樣靜靜地躺著燕偶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪础嫡。 梳的紋絲不亂的頭發(fā)上指么,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音榴鼎,去河邊找鬼伯诬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛巫财,可吹牛的內(nèi)容都是我干的盗似。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼平项,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼赫舒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闽瓢,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤接癌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后扣讼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缺猛,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年椭符,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荔燎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡销钝,死狀恐怖湖雹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曙搬,我是刑警寧澤摔吏,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布鸽嫂,位于F島的核電站,受9級(jí)特大地震影響征讲,放射性物質(zhì)發(fā)生泄漏据某。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一诗箍、第九天 我趴在偏房一處隱蔽的房頂上張望癣籽。 院中可真熱鬧,春花似錦滤祖、人聲如沸筷狼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埂材。三九已至,卻和暖如春汤求,著一層夾襖步出監(jiān)牢的瞬間俏险,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工扬绪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竖独,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓挤牛,卻偏偏與公主長(zhǎng)得像莹痢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子墓赴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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

  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成一個(gè)進(jìn)程.進(jìn)程是處于運(yùn)行過程中...
    勝浩_ae28閱讀 5,108評(píng)論 0 23
  • 輕量級(jí)線程:協(xié)程 在常用的并發(fā)模型中竣蹦,多進(jìn)程、多線程沧奴、分布式是最普遍的痘括,不過近些年來逐漸有一些語言以first-c...
    Tenderness4閱讀 6,364評(píng)論 2 10
  • iOS多線程編程 基本知識(shí) 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,就是一段程序的執(zhí)...
    陵無山閱讀 6,048評(píng)論 1 14
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評(píng)論 1 18
  • 頹廢的石頭 文||與你相識(shí) 寫滿滄桑 早已被遺忘 青苔和蛛網(wǎng) 覆滿胸膛 會(huì)不會(huì)想昔日時(shí)光 你曾經(jīng)光彩奪目 也被萬人...
    與你相識(shí)_40fa閱讀 194評(píng)論 2 1