zengbin93 / blog

17 stars 10 forks source link

笔记 - Python - APScheduler - 跨平台任务调度 #33

Open zengbin93 opened 6 years ago

zengbin93 commented 6 years ago

APScheduler是Python中的跨平台任务调度框架,常用于执行一些复杂的定时任务。

参考资料

 

zengbin93 commented 6 years ago

四个基本模块

四个模块:1)触发器 - triggers;2)任务存储 - job stores;3)执行器 - executors;4)调度程序- schedulers。

模块 简单介绍
triggers 描述一个任务何时被触发,有按日期、按时间间隔、按cronjob描述式三种触发方式
job stores 任务持久化仓库,默认保存任务在内存中,也可将任务保存都各种数据库中,任务中的数据序列化后保存到持久化数据库,从数据库加载后又反序列化。
executors 执行任务模块,当任务完成时executors通知schedulers,schedulers收到后会发出一个适当的事件
schedulers 任务调度器,通过它配置job stores和executors,添加、修改和删除任务

关于这四个模块的详细介绍,请查看: http://apscheduler.readthedocs.io/en/latest/userguide.html#basic-concepts

调度器scheduler的选择

scheduler usage scene
BlockingScheduler use when the scheduler is the only thing running in your process
BackgroundScheduler use when you’re not using any of the frameworks below, and want the scheduler to run in the background inside your application
AsyncIOScheduler use if your application uses the asyncio module
GeventScheduler use if your application uses gevent
TornadoScheduler use if you’re building a Tornado application
TwistedScheduler use if you’re building a Twisted application
QtScheduler use if you’re building a Qt application

任务存储 job stores的选择

job stores 的主要选择依据:需不需要持久化任务。 如果不需要,直接使用默认的 Memory 储存任务;反之,推荐使用PostgreSQL进行任务存储,因为它有着很强的数据完整性保护。

对于持久化job stores,以下都是可选方案:

执行器 executors的选择

默认是ThreadPoolExecutor;如果有CPU密集型的操作,推荐使用ProcessPoolExecutor;两者同时用也是可以的。

触发器 triggers的选择

内置了三种触发器

trigger usage scene
date use when you want to run the job just once at a certain point of time
interval use when you want to run the job at fixed intervals of time
cron use when you want to run the job periodically at certain time(s) of day

 

配置调度器scheduler

 三种配置方式:1)使用字典参数(use a configuration dictionary);2)直接传递关键词参数(pass in the options as keyword arguments);3)先实例化一个scheduler,然后在添加任务和配置。

这里有一个用这三种方式配置scheduler的案例: http://apscheduler.readthedocs.io/en/latest/userguide.html#configuring-the-scheduler   给调度器添加任务有两种方式:1)直接调用add_job()方法;2)使用scheduled_job()装饰器。

区别在于,第一种方法添加任务之后会返回一个apscheduler.job.Job实例,可以对任务进行修改或删除;第二种方法添加任务相对简便,但是添加后不能在运行时修改或删除。

 

 

zengbin93 commented 6 years ago

案例 - 每3秒执行一次print任务

演示了三种触发器的使用方法。

from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
import os

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

# -----------------------------------------------
# 使用cron
if __name__ == '__main__':
    scheduler = BlockingScheduler()
    scheduler.add_job(tick,'cron', second='*/3', hour='*')    
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    try:
        scheduler.start()
    except (KeyboardInterrupt, SystemExit):
        scheduler.shutdown()

# -----------------------------------------------
# 使用intervel
if __name__ == '__main__':
    scheduler = BlockingScheduler()
    # 设定next_run_time参数,可以指定时间启动一次任务
    scheduler.add_job(tick,'interval', seconds=3, next_run_time=datetime.now())    
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    try:
        scheduler.start()
    except (KeyboardInterrupt, SystemExit):
        scheduler.shutdown()
# -----------------------------------------------
# 使用date  (仅执行一次)
if __name__ == '__main__':
    scheduler = BlockingScheduler()
    scheduler.add_job(tick,'date', run_date = datetime(2017,6,20,16,36,12))    
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    try:
        scheduler.start()
    except (KeyboardInterrupt, SystemExit):
        scheduler.shutdown()
zengbin93 commented 6 years ago

案例 - 使用装饰器添加任务

from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
import os

sched = BlockingScheduler()

# 使用cron
@sched.scheduled_job('cron',id='Tick',second='*/3',minute='58,34')
def tick():
    print('Tick! The time is: %s' % datetime.now())

print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
try:
    sched.start()
except (KeyboardInterrupt, SystemExit):
    sched.shutdown()