前言
APScheduler基於Quartz的一個Python定時任務框架,實現了Quartz的所有功能,使用起來十分方便。提供了基於日期、固定時間間隔以及crontab類型的任務,不僅可以添加、刪除定時任務,還可以將任務存儲到數據庫中、實現任務的持久化。基於這些功能,我們可以很方便的實現一個python定時任務系統。
安裝
1、利用pip進行安裝
pip install apscheduler
2、 APScheduler有四種組成部分:
triggers(觸發器):
觸發器包含調度邏輯,每一個作業有它自己的觸發器,用於決定接下來哪一個作業會運行,除了他們自己初始化配置外,觸發器完全是無狀態的。
job stores(作業存儲):
用來存儲被調度的作業,默認的作業存儲器是簡單地把作業任務保存在內存中,其它作業存儲器可以將任務作業保存到各種數據庫中,支持MongoDB、Redis、SQLAlchemy存儲方式。當對作業任務進行持久化存儲的時候,作業的數據將被序列化,重新讀取作業時在反序列化。
executors(執行器):
執行器用來執行定時任務,只是將需要執行的任務放在新的線程或者線程池中運行。當作業任務完成時,執行器將會通知調度器。對於執行器,默認情況下選擇ThreadPoolExecutor就可以了,但是如果涉及到一下特殊任務如比較消耗CPU的任務則可以選擇ProcessPoolExecutor,當然根據根據實際需求可以同時使用兩種執行器。
schedulers(調度器):
調度器是將其它部分聯系在一起,一般在應用程序中只有一個調度器,應用開發者不會直接操作觸發器、任務存儲以及執行器,相反調度器提供了處理的接口。通過調度器完成任務的存儲以及執行器的配置操作,如可以添加。修改、移除任務作業。
3、 APScheduler提供了七種調度器:
BlockingScheduler:適合於只在進程中運行單個任務的情況,通常在調度器是你唯一要運行的東西時使用。
BackgroundScheduler: 適合於要求任何在程序后台運行的情況,當希望調度器在應用后台執行時使用。
AsyncIOScheduler:適合於使用asyncio異步框架的情況
GeventScheduler: 適合於使用gevent框架的情況
TornadoScheduler: 適合於使用Tornado框架的應用
TwistedScheduler: 適合使用Twisted框架的應用
QtScheduler: 適合使用QT的情況
4、APScheduler提供了四種存儲方式:
MemoryJobStore
sqlalchemy
mongodb
redis
5、APScheduler提供了三種任務觸發器:
data:固定日期觸發器:任務只運行一次,運行完畢自動清除;若錯過指定運行時間,任務不會被創建
interval:時間間隔觸發器,每隔多長時間觸發一次
cron:cron風格的任務觸發 ,可以每天早上固定時間點執行一次任務
interval:時間間隔觸發器,每隔多長時間觸發一次
cron:cron風格的任務觸發 ,可以每天早上固定時間點執行一次任務
(5.1)data
固定時間調度(作業只會執行一次)
import time from apscheduler.schedulers.blocking import BlockingScheduler def my_job(): print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) sched = BlockingScheduler() ## 采用dete固定時間模式,在特定時間只執行一次 sched.add_job(my_job, 'date', run_date='2019-01-01 00:00:00) sched.start()
(5.2)interval
例如每隔五秒執行一次:
import time from apscheduler.schedulers.blocking import BlockingScheduler def my_job(): print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) #### 采用interval固定間隔模式,每隔五秒只執行一次 sched.add_job(my_job, 'interval', seconds=5) sched.start()
間隔調度,參數如下:
weeks (int) – 間隔幾周
days (int) – 間隔幾天
hours (int) – 間隔幾小時
minutes (int) – 間隔幾分鍾
seconds (int) – 間隔多少秒
start_date (datetime|str) – 開始日期
end_date (datetime|str) – 結束日期
timezone (datetime.tzinfo|str) – 時區
(5.3)cron
定時調度(例如在每一天上午八點半或者12點半執行任務)
import time from apscheduler.schedulers.blocking import BlockingScheduler scheduler = BlockingScheduler() def everyday_crawler_job(): print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) # subprocess.call("python Crawler.py") sched = BlockingScheduler() #每隔一天 執行抓包程序 # sched.add_job(everyday_crawler_job, 'interval', days=1)days #每天早上八點半和十二點半各執行一次抓包程序 sched.add_job(everyday_crawler_job, 'cron', hour='8, 12', minute='30') sched.start()
參數如下:
(int|str) 表示參數既可以是int類型,也可以是str類型 (datetime | str) 表示參數既可以是datetime類型,也可以是str類型 year (int|str) – 4-digit year -(表示四位數的年份,如2008年) month (int|str) – month (1-12) -(表示取值范圍為1-12月) day (int|str) – day of the (1-31) -(表示取值范圍為1-31日) week (int|str) – ISO week (1-53) -(格里歷2006年12月31日可以寫成2006年-W52-7(擴展形式)或2006W527(緊湊形式)) day_of_week (int|str) – number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun) - (表示一周中的第幾天,既可以用0-6表示也可以用其英語縮寫表示) hour (int|str) – hour (0-23) - (表示取值范圍為0-23時) minute (int|str) – minute (0-59) - (表示取值范圍為0-59分) second (int|str) – second (0-59) - (表示取值范圍為0-59秒) start_date (datetime|str) – earliest possible date/time to trigger on (inclusive) - (表示開始時間) end_date (datetime|str) – latest possible date/time to trigger on (inclusive) - (表示結束時間) timezone (datetime.tzinfo|str) – time zone to use for the date/time calculations (defaults to scheduler timezone) -(表示時區取值)
cron其他參數格式用法示例如下:
#表示2017年3月22日17時19分07秒執行該程序 sched.add_job(my_job, 'cron', year=2017,month = 03,day = 22,hour = 17,minute = 19,second = 07) #表示任務在6,7,8,11,12月份的第三個星期五的00:00,01:00,02:00,03:00 執行該程序 sched.add_job(my_job, 'cron', month='6-8,11-12', day='3rd fri', hour='0-3') #表示從星期一到星期五5:30(AM)直到2014-05-30 00:00:00 sched.add_job(my_job(), 'cron', day_of_week='mon-fri', hour=5, minute=30,end_date='2014-05-30') #表示每5秒執行該程序一次,相當於interval 間隔調度中seconds = 5 sched.add_job(my_job, 'cron',second = '*/5')
在設置定時調度任務時遇到一個問題,定時任務未執行打印的log如下:
Run time of job "everyday_crawler_job (trigger: cron[hour='8,12', minute='30'], next run at: 2019-01-30 08:30:00 CST)" was missed by 0:00:01.084138
這個log的意思是:距離下次運行時間,錯過了1秒,所有第二次就沒有執行任務
解決方法:
在add_job()中添加參數:
解決方法:
在add_job()中添加參數:
misfire_grace_time: 主要就是為了解決這個was missed by 這個報錯,添加允許容錯的時間,單位為:s
coalesce:如果系統因某些原因沒有執行任務,導致任務累計,為True則只運行最后一次,為False 則累計的任務全部跑一遍
定時任務的停止
如果我們在終端中直接執行的話,關閉終端窗口,Python任務就會中斷,Python進程會被殺死,程序將停止運行。如果我們用編輯器直接運行python腳本,這樣執行后,如果未正確取消進程,關閉編輯器后,程序依舊運行。
進程id:3057
$ kill 3057
如果運行后忘記進程ID,則可遵循下面的方法進行停止
ps -e | grep python
這樣將會在終端列出python相關的進程:
$ ps -e | grep python
1025 ?? 0:00.41
1602 ?? 0:00.37
17699 ttys001 0:00.00 grep python
然后分別執行kill就可以了
