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就可以了

  • 相关阅读:
    临时表空间占用大量空间(新建)
    学习总结
    sql:表关联方式
    11gR2 Clusterware 和 Grid Home
    sql分析常用查询
    通过 SSH 实现 TCP / IP 隧道(端口转发):使用 OpenSSH 可能的 8 种场景
    Fabric部署环境初始化(Centos 7)
    Fabric 学习路线
    代币智能合约(go)
    springboot切面编程范例
  • 原文地址:https://www.cnblogs.com/xinzaiyuan/p/13470657.html
Copyright © 2011-2022 走看看