Python進階(9) 定時運行程序 APScheduler


1. 前言

  • 官網源碼官方examples
  • 安裝pip install apscheduler
  • 組件介紹
    • triggers:什麼時候觸發任務。
    • job stores:默認情況下將任務保存在內存中。還沒用到需要序列化到數據庫的情況。
    • executors:執行Job,主要取決於用了什麼框架。默認使用線程池,常用的還有進程池。
    • schedulers:用於管理以上三個組件。

1. Scheduler

1.1. 基本概念

  • 作用:用於管理 triggers,job stores,executors。
  • 如何選擇:主要就是根據運行的環境來選擇。
    • BlockingScheduler:程序只有調度器運行時選擇。
    • BackgroundScheduler:沒有使用其他框架,且希望調度器在應用後臺運行。

1.2. 基本API

  • 所有的Scheduler都繼承自 BaseScheduler
  • 初始化函數 def __init__(self, gconfig={}, **options):
    • gconfig 可以看做是一個全局初始化參數。
    • **options 可以看做是自定義初始化參數。
    • 上面兩者所包含的參數是完全相同的,且自定義初始化參數會覆蓋全局初始化參數。
    • 包含的參數有:
      • logger:str/logging.Logger,用於輸出日誌信息。
      • timezone:str/datetime.tzinfo,指定時區。
      • jobstore_retry_interval:int/float,當job store拋出異常時,最短的重試時間間隔。
      • job_defaults:dict,新建jobs的默認參數
      • jobstores:dict,job store alias -> job store instance or configuration dict
      • executors:dict, executor alias -> executor instance or configuration dict
  • configure(gconfig={}, prefix='apscheduler.', **options):在開始運行前設置參數。
    • 參數類型與初始化時相同。
  • start(paused=False):運行scheduler。
    • 如果paused=True則需要等到運行 resume() 方法後纔會真正運行scheduler。
  • shutdown(wait=True):關閉scheduler
    • 同時關閉了 executors和job stores。
    • 不會停止正在運行的jobs。
    • wait=True時會等待所有jobs運行完成。
  • pause():暫停,與resume()配合使用。
  • resume():重新開始,與pause()配合使用。
  • add/remove_executor
  • add/remove_jobstore
  • add/remove_listener
  • job相關API
    • add_job():參數太多
      • func
      • trigger:str或trigger對象,初始化參數通過 **trigger_args 來獲得。
      • argsfunc 參數
      • kwargsfunc 參數
      • id
      • name
      • misfire_grace_timec
      • coalesce
      • max_instances
      • next_run_time
      • jobstore:str,通過 alias 來選擇。
      • executor:str,通過 alias 來選擇。
      • replace_existing
      • **trigger_args:用於 trigger
    • modify_job(job_id, jobstore=None, **changes)
      • 改變某個job的參數。
    • reschedule_job(job_id, jobstore=None, trigger=None, **trigger_args)
      • 改變某個job的trigger,並修改下次運行時間。.
    • pause/resume_job:暫停/繼續某個job。
    • get_jobs(jobstore=None, pending=None)
    • get_job(job_id, jobstore=None)
    • remove_job(job_id, jobstore=None)
    • remove_all_jobs(jobstore=None)
    • print_jobs(jobstore=None, out=sys.stdout)

1.3. 實例

from datetime import datetime
import time
import os

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.blocking import BlockingScheduler

def tick():
    print('Tick! The time is: %s' % datetime.now())


# background sheculer 實例
scheduler = BackgroundScheduler()
scheduler.add_job(tick, 'interval', seconds=3)
scheduler.start()
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
try:
    # This is here to simulate application activity (which keeps the main thread alive).
    while True:
        time.sleep(2)
except (KeyboardInterrupt, SystemExit):
    # Not strictly necessary if daemonic mode is enabled but should be done if possible
    scheduler.shutdown()

# blocking sheduler 實例
scheduler = BlockingScheduler()
scheduler.add_job(tick, 'interval', seconds=3)
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))

try:
    scheduler.start()
except (KeyboardInterrupt, SystemExit):
    pass

2. trigger

2.1. 基本概念

  • 基本作用:決定job運行的時間點/時間間隔。
  • 分類
    • cron:功能最強大,可以指定時間、時間間隔、時間範圍等。參考
    • date:指定某個時間點出發,只執行一次。
    • interval:指定時間間隔出發任務,可指定時間範圍。

2.2. apscheduler.triggers.cron.CronTrigger

  • 參數很多,功能強大。
  • 對我來說,因爲在linux中也常用,所以我用起來也最順手。
  • 主要參數:
    • year:int/str,4位
    • month:int/str,[1, 12]
    • day:int/str,[1, 31]
    • week:int/str,[1, 53]
    • day_of_week:int/str,[0, 6],從週一開始,也可以用英文的錢三個小寫字母。
    • hour:int/str,[0, 23]
    • minute:int/str,[0, 59]
    • second:int/str,[0, 59]
    • start_date:datetime/str
    • end_date:datetime/str
    • timezone:datetime.tzinfo|str
    • jitter:int/None,運行時間隨機偏移[-jitter, jitter]秒。
  • 對於沒有指定的參數,根據輸入參數分別設置爲*或最小值:
    • 大於指定元素中最小的,設置爲 *
    • 小於指定元素中最小的,設置爲其最小值。
    • 舉例:輸入 day=1, minute=20,則設置second=0,其他元素爲*
  • 其他常用的一些語法
    |Expression|Field|Description|
    |:–|:-😐:–|
    |*|any|fire on every value|
    |*/a|any|Fire every a values, starting from the minimum|
    |a-b|any|Fire on any value within the a-b range (a must be smaller than b)|
    |a-b/c|any|Fire every c values within the a-b range|
    |xth y|day|Fire on the x -th occurrence of weekday y within the month|
    |last x|day|Fire on the last occurrence of weekday x within the month|
    |last|day|Fire on the last day within the month|
    |x,y,z|any|Fire on any matching expression; can combine any number of any of the above expressions|

2.3. 其他 trigger

  • apscheduler.triggers.interval.IntervalTrigger
    • 通過設置間隔時間來確定下次運行時間。
    • 主要參數:
      • weeks:int
      • days:int
      • hours:int
      • minutes:int
      • seconds:int
      • start_date:datetime/str
      • end_date:datetime/str
      • timezone:datetime.tzinfo|str
      • jitter:int/None,運行時間隨機偏移[-jitter, jitter]秒。
  • apscheduler.triggers.date.DateTrigger(run_date=None, timezone=None)
    • 只在給定的時間運行一次
    • run_date:datetime|str,指定運行時間。
    • timezone:datetime.tzinfo|str
  • 集合操作:
    • apscheduler.triggers.combining.AndTrigger(triggers, jitter=None)
    • apscheduler.triggers.combining.OrTrigger(triggers, jitter=None)
    • 主要就是用於合併多個 triiger。

2.5. 舉例:add_job 中trigger的應用

  • 回顧一下 scheduler.add_job 方法,與trigger有關的參數有:
    • trigger=None
      • 可以設置爲字符串 date/interval/cron
      • 也可以設置爲上面提到過的各種 trigger 對象。
    • **trigger_args:即 add_job 方法中所有沒有定義的命名參數都會作爲trigger對象的參數導入。
  • 舉例:
# date
# 方法一
sched.add_job(my_job, 'date', run_date=datetime(2009, 11, 6, 16, 30, 5), args=['text'])
# 方法二
sched.add_job(my_job, 'date', run_date='2009-11-06 16:30:05', args=['text'])
# 方法三(馬上執行)
sched.add_job(my_job, args=['text'])

# interval
# 方法一
sched.add_job(job_function, 'interval', hours=2, start_date='2010-10-10 09:30:00', end_date='2014-06-15 11:00:00')
# 方法二
@sched.scheduled_job('interval', id='my_job_id', hours=2)
def job_function():
    print("Hello World")

# cron
# 方法一
sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour=5, minute=30, end_date='2014-05-30')
# 方法二
@sched.scheduled_job('cron', id='my_job_id', day='last sun')
def some_decorated_task():
    print("I am printed at 00:00:00 on the last Sunday of every month!")
# 方法三
sched.add_job(job_function, CronTrigger.from_crontab('0 0 1-15 may-aug *'))

# AndTrigger
trigger = AndTrigger([IntervalTrigger(hours=2),
                      CronTrigger(day_of_week='sat,sun')])
scheduler.add_job(job_function, trigger)

# OrTrigger
trigger = OrTrigger([CronTrigger(day_of_week='mon', hour=2),
                     CronTrigger(day_of_week='tue', hour=15)])
scheduler.add_job(job_function, trigger)

3. executors & job store

3.1. Executors

  • 用於指定通過什麼後端來執行任務。
  • 常用的有:線程池與進程池。
    • 默認使用線程池。
  • 如何使用:
    • 第一步:在定義 scheduler 時輸入 executors 參數。
      • 該參數是一個字典,key爲executor的別名,value爲executors的對象。
    • 第二步:在 add_job 的時候指定對應executor的別名。
  • 其他:
    • 默認情況下,用線程池已經夠了。
    • 計算密集型任務要使用進程池。

3.2. Job Stores

  • 作用:將job保存到哪裏。
    • 可以保存到各類數據庫中。因爲沒用到,所以沒細看。
    • 默認保存到內存中。
  • 如何使用:
    • 第一步:在定義 scheduler 時輸入 jobstores 參數。
      • 該參數是一個字典,key爲executor的別名,value爲executors的對象。
    • 第二步:在 add_job 的時候指定對應jobstore的別名。

3.3. 舉例

from pytz import utc

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor


jobstores = {
    'mongo': {'type': 'mongodb'},
    'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}

executors = {
    'default': {'type': 'threadpool', 'max_workers': 20},
    'processpool': ProcessPoolExecutor(max_workers=5)
}
# executors = {
#     'default': ThreadPoolExecutor(20),
#     'processpool': ProcessPoolExecutor(5)
# }

job_defaults = {
    'coalesce': False,
    'max_instances': 3
}
scheduler = BackgroundScheduler()

# .. do something else here, maybe add jobs etc.

scheduler.configure(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章