• APScheduler的使用


    定时框架APScheduler

    APSScheduler是python的一个定时任务框架,它提供了基于日期date、固定时间间隔interval、以及linux上的crontab类型的定时任务。该框架不仅可以添加、删除定时任务,还可以将任务存储到数据库中、实现任务的持久化。

    APScheduler有四种组件

    • triggers(触发器):触发器包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行,除了他们自己初始化配置外,触发器完全是无状态的。

    • job stores(作业存储):用来存储被调度的作业,默认的作业存储器是简单地把作业任务保存在内存中,其它作业存储器可以将任务作业保存到各种数据库中,支持MongoDB、Redis、SQLAlchemy存储方式。当对作业任务进行持久化存储的时候,作业的数据将被序列化,重新读取作业时在反序列化。

    • executors(执行器):执行器用来执行定时任务,只是将需要执行的任务放在新的线程或者线程池中运行。当作业任务完成时,执行器将会通知调度器。对于执行器,默认情况下选择ThreadPoolExecutor就可以了,但是如果涉及到一下特殊任务如比较消耗CPU的任务则可以选择ProcessPoolExecutor,当然根据根据实际需求可以同时使用两种执行器。

    • schedulers(调度器):调度器是将其它部分联系在一起,一般在应用程序中只有一个调度器,应用开发者不会直接操作触发器、任务存储以及执行器,相反调度器提供了处理的接口。通过调度器完成任务的存储以及执行器的配置操作,如可以添加。修改、移除任务作业

    APScheduler提供了七种调度器

    • BlockingScheduler:适合于只在进程中运行单个任务的情况,通常在调度器是你唯一要运行的东西时使用。
    • BackgroundScheduler: 适合于要求任何在程序后台运行的情况,当希望调度器在应用后台执行时使用。
    • AsyncIOScheduler:适合于使用asyncio异步框架的情况
    • GeventScheduler: 适合于使用gevent框架的情况
    • TornadoScheduler: 适合于使用Tornado框架的应用
    • TwistedScheduler: 适合使用Twisted框架的应用
    • QtScheduler: 适合使用QT的情况

    APScheduler提供了四种存储方式

    • MemoryJobStore
    • sqlalchemy
    • mongodb
    • redis

    APScheduler提供了三种任务触发器

    • data:固定日期触发器:任务只运行一次,运行完毕自动清除;若错过指定运行时间,任务不会被创建
    • interval:时间间隔触发器
    • cron:cron风格的任务触发

    示例

    示例1 BlockingScheduler

    • BlockingScheduler:在进程中运行单个任务,调度器是唯一运行的东西
    • 该示例代码生成了一个BlockingScheduler调度器,使用了默认的任务存储MemoryJobStore,以及默认的执行器ThreadPoolExecutor,并且最大线程数为10。

    定义job

    def jod1():
        print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' #####job1 ' + str(random.randint(0, 10)))
    

    定义run方法

    def run1():
        scheduler = BlockingScheduler()
        scheduler.add_job(jod1, 'interval', seconds=5)
        scheduler.start()
    

    完整代码

    import time
    import random
    from apscheduler.schedulers.blocking import BlockingScheduler
    
    
    def jod1():
        print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' #####job1 ' + str(random.randint(0, 10)))
    
    
    def run1():
        scheduler = BlockingScheduler()
        scheduler.add_job(jod1, 'interval', seconds=5)
        scheduler.start()
    
    
    if __name__ == '__main__':
        run1()
    

    运行结果

    2019-05-16 11:09:05 #####job1 2
    2019-05-16 11:09:10 #####job1 5
    2019-05-16 11:09:15 #####job1 1
    2019-05-16 11:09:20 #####job1 0
    2019-05-16 11:09:25 #####job1 8
    2019-05-16 11:09:30 #####job1 0
    2019-05-16 11:09:35 #####job1 9
    2019-05-16 11:09:40 #####job1 1
    2019-05-16 11:09:45 #####job1 4
    ......
    

    测试1

    我们在示例1的基础上再加一个job2,看看什么情况

    job2示例代码

    def jod2():
        print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' #####job2 ' + str(random.randint(0, 10)))
    

    run2示例代码

    def run2():
        scheduler = BlockingScheduler()
        scheduler.add_job(jod1, 'interval', seconds=5)
        scheduler.add_job(jod2, 'interval', seconds=5)
        scheduler.start()
    

    实行结果:

    2019-05-16 11:10:46 #####job2 9
    2019-05-16 11:10:46 #####job1 2
    2019-05-16 11:10:51 #####job2 3
    2019-05-16 11:10:51 #####job1 2
    2019-05-16 11:10:56 #####job2 9
    2019-05-16 11:10:56 #####job1 1
    2019-05-16 11:11:01 #####job2 9
    2019-05-16 11:11:01 #####job1 1
    2019-05-16 11:11:06 #####job2 2
    2019-05-16 11:11:06 #####job1 5
    2019-05-16 11:11:11 #####job2 6
    2019-05-16 11:11:11 #####job1 7
    2019-05-16 11:11:16 #####job2 1
    2019-05-16 11:11:16 #####job1 6
    ......
    

    从执行结果来看,在同一个调度器中添加2个job,这两个job会在同一时刻同时执行

    测试2

    我们将job的运行时间强制改为6秒,看看调度器会怎么处理

    修改后的job1

    def jod1():
        print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' #####job1 ' + str(random.randint(0, 10)))
        time.sleep(6)
    

    run1 不变,运行结果

    2019-05-16 11:18:11 #####job1 1
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 11:18:16 CST)" skipped: maximum number of running instances reached (1)
    2019-05-16 11:18:21 #####job1 9
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 11:18:26 CST)" skipped: maximum number of running instances reached (1)
    2019-05-16 11:18:31 #####job1 5
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 11:18:36 CST)" skipped: maximum number of running instances reached (1)
    2019-05-16 11:18:41 #####job1 0
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 11:18:46 CST)" skipped: maximum number of running instances reached (1)
    

    从执行结果来看,由于job的运行时间超过了执行器需要执行时的时间,所以本次任务跳过,就变成了10秒执行一次的任务了。

    示例2 BackgroundScheduler

    完整示例:

    import time
    import random
    from apscheduler.schedulers.blocking import BlockingScheduler
    from apscheduler.schedulers.background import BackgroundScheduler
    
    
    def jod1():
        print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' #####job1 ' + str(random.randint(0, 10)))
        time.sleep(6)
        
    def run3():
        scheduler = BackgroundScheduler()
        scheduler.add_job(jod1, 'interval', seconds=5)
        scheduler.start()
    
        while True:
            print('main-start:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            time.sleep(2)
            print('main-end:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            
    
    if __name__ == '__main__':
        # run1()
        # run2()
        run3()
    

    测试1

    开启一个任务,然后另外开启一个线程

    def run3():
        scheduler = BackgroundScheduler()
        scheduler.add_job(jod1, 'interval', seconds=5)
        scheduler.start()
    
        while True:
            print('main-start:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            time.sleep(2)
            print('main-end:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    

    运行结果

    main-start: 2019-05-16 18:42:13
    main-end: 2019-05-16 18:42:15
    main-start: 2019-05-16 18:42:15
    main-end: 2019-05-16 18:42:17
    main-start: 2019-05-16 18:42:17
    2019-05-16 18:42:18 #####job1 6
    main-end: 2019-05-16 18:42:19
    main-start: 2019-05-16 18:42:19
    main-end: 2019-05-16 18:42:21
    main-start: 2019-05-16 18:42:21
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 18:42:23 CST)" skipped: maximum number of running instances reached (1)
    main-end: 2019-05-16 18:42:23
    main-start: 2019-05-16 18:42:23
    main-end: 2019-05-16 18:42:25
    main-start: 2019-05-16 18:42:25
    main-end: 2019-05-16 18:42:27
    main-start: 2019-05-16 18:42:27
    2019-05-16 18:42:28 #####job1 5
    main-end: 2019-05-16 18:42:29
    main-start: 2019-05-16 18:42:29
    main-end: 2019-05-16 18:42:31
    main-start: 2019-05-16 18:42:31
    Execution of job "jod1 (trigger: interval[0:00:05], next run at: 2019-05-16 18:42:33 CST)" skipped: maximum number of running instances reached (1)
    main-end: 2019-05-16 18:42:33
    main-start: 2019-05-16 18:42:33
    main-end: 2019-05-16 18:42:35
    main-start: 2019-05-16 18:42:35
    main-end: 2019-05-16 18:42:37
    main-start: 2019-05-16 18:42:37
    2019-05-16 18:42:38 #####job1 1
    ......
    

    示例3 采用cron的方式

    采用cron的方式来调度任务

    def run4():
        scheduler = BackgroundScheduler()
        scheduler.add_job(jod1, 'cron', day_of_week='fri', second='*/5')
        scheduler.start()
    
        while True:
            print('main-start:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            time.sleep(2)
            print('main-end:', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    
    不积跬步,无以至千里。
  • 相关阅读:
    jQuery UI (7)Autocomplete 自动补全插件
    jQuery UI (6)Accodion 可折叠面板插件
    jQuery UI (5)Sortable 排序插件
    jQuery UI (4)Jquery UI Selectable 选择插件
    jQuery UI (3)Resiable 调整大小插件
    jQuery UI (2)Droppable 放置插件
    jQuery UI (1)Draggable 拖动插件
    C#(99):Lambda表达式
    C#(99):四种Timer的区别和用法
    C#(99):Reporting Service编程----访问Web服务
  • 原文地址:https://www.cnblogs.com/DeaconOne/p/10876638.html
Copyright © 2020-2023  润新知