zoukankan      html  css  js  c++  java
  • APScheduler定时任务框架的使用

    前言

    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风格的任务触发 ,可以每天早上固定时间点执行一次任务

     (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()中添加参数:
    misfire_grace_time: 主要就是为了解决这个was missed by 这个报错,添加允许容错的时间,单位为:s
    coalesce如果系统因某些原因没有执行任务,导致任务累计,为True则只运行最后一次,为False 则累计的任务全部跑一遍

    定时任务的停止

    如果我们在终端中直接执行的话,关闭终端窗口,Python任务就会中断,Python进程会被杀死,程序将停止运行。如果我们用编辑器直接运行python脚本,这样执行后,如果未正确取消进程,关闭编辑器后,程序依旧运行。
     
    如何停止呢,可使用如下方法:
    如果知道进程id直接只用kill命令结束即可,例如:
    进程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就可以了

  • 相关阅读:
    EBS SQL > Form & Report
    oracle sql 优化分析点
    MRP 物料需求计划
    MRPII 制造资源计划
    Barcode128 应用实务
    Oracle SQL语句优化技术分析
    APPSQLAP10710 Online accounting could not be created. AP Invoice 无法创建会计分录
    Oracle数据完整性和锁机制
    ORACLE Responsibility Menu Reference to Other User
    EBS 常用 SQL
  • 原文地址:https://www.cnblogs.com/xinzaiyuan/p/13470657.html
Copyright © 2011-2022 走看看