Python轻量级任务调度框架apscheduler的简单使用

                                   Python轻量级任务调度框架apscheduler的简单使用

APScheduler(Advanced Python Scheduler)是一个轻量级的Python定时任务调度框架(Python库)。
APScheduler有三个内置的调度系统,其中包括:

  • cron式调度(可选开始/结束时间)
  • 基于间隔的执行(以偶数间隔运行作业,也可以选择开始/结束时间)
  • 一次性延迟执行任务(在指定的日期/时间内运行作业一次)

支持后端存储任务并灵活调度

APScheduler可以任意混合和匹配调度系统和作业存储的后端,其中支持后端存储作业包括:

  • Memory
  • SQLAlchemy
  • MongoDB
  • Redis
  • RethinkDB
  • ZooKeeper
  • sqlite

也就是说该库十分灵活,可以使用后端数据库存储任务,以随时的编排并调度各类任务。

集成的Python框架

APScheduler内继承了几个常见的Python框架:

  • asyncio
  • gevent
  • tornado
  • qt

支持以django和flask插件形式集成到Django和flask,当然了,既然都是这两个著名框架的插件了,自然可以使用其自带的开发数据库sqlite进行任务的持久化。也就是上面所提到的后端存储任务作业。

各组件简介

调度器

  • BlockingScheduler : 当调度器是你应用中唯一要运行的东西时。
  • BackgroundScheduler : 当你没有运行任何其他框架并希望调度器在你应用的后台执行时使用(充电桩即使用此种方式)。
  • AsyncIOScheduler : 当你的程序使用了asyncio(一个异步框架)的时候使用。
  • GeventScheduler : 当你的程序使用了gevent(高性能的Python并发框架)的时候使用。
  • TornadoScheduler : 当你的程序基于Tornado(一个web框架)的时候使用。
  • TwistedScheduler : 当你的程序使用了Twisted(一个异步框架)的时候使用
  • QtScheduler : 如果你的应用是一个Qt应用的时候可以使用。

这里需要强调一下,blocking和background是最为常用的两个调度器

作业存储器,我喜欢说这个是后端存储任务作业

扫描二维码关注公众号,回复: 12967376 查看本文章

如果你的应用在每次启动的时候都会重新创建作业,那么使用默认的作业存储器(MemoryJobStore)即可,但是如果你需要在调度器重启或者应用程序奔溃的情况下任然保留作业,你应该根据你的应用环境来选择具体的作业存储器。例如:使用Mongo或者SQLAlchemy JobStore (用于支持大多数RDBMS)

执行器

对执行器的选择取决于你使用上面哪些框架,大多数情况下,使用默认的ThreadPoolExecutor已经能够满足需求。如果你的应用涉及到CPU密集型操作,你可以考虑使用ProcessPoolExecutor来使用更多的CPU核心。你也可以同时使用两者,将ProcessPoolExecutor作为第二执行器。

触发器

当你调度作业的时候,你需要为这个作业选择一个触发器,用来描述这个作业何时被触发,APScheduler有三种内置的触发器类型:

  • date 一次性指定日期
  • interval 在某个时间范围内间隔多长时间执行一次
  • cron 和Linux crontab格式兼容,最为强大,也就是Linux的crontab写法,也是最为常用的触发器。

那么,任务计划,顾名思义是至少需要任务或者任务集和触发器两者组成。触发器可以是某一个时刻,也可以是在某一个时间段内,也可以像Linux的crontab一样,灵活的指定时间。下面就开始初识apscheduler之旅吧~~~~~~~~!!!!!

在安装之前,我需要废话一句,前面说了这是一个轻量级的框架(库),一般轻量的另一层含义是用法灵活,因此,想要用好这个apscheduler任务调度器框架会有更多的困难哦

apscheduler的安装:

https://pan.baidu.com/s/1tPNO53Ufhty863tvtHLGgA 提取码:apsc  这个是apscheduler的离线安装包(离线安装包的使用命令为进入安装包目录后,pip install ./*.whl)

https://pan.baidu.com/s/1owRzHB4r29CKlc-vBQcbqQ 提取码:pipe 这个是pip的离线安装包(这个离线安装先安装pip的rpm,然后在安装whl文件),下面的安装是通过网络安装的方式安装。

pip install APScheduler-3.7.0-py2.py3-none-any.whl

[root@centos6 ~]# pip install APScheduler-3.7.0-py2.py3-none-any.whl 
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Looking in indexes: http://mirrors.aliyun.com/pypi/simple/
Processing ./APScheduler-3.7.0-py2.py3-none-any.whl
Requirement already satisfied: setuptools>=0.7 in /usr/lib/python2.7/site-packages (from APScheduler==3.7.0) (0.9.8)
Collecting funcsigs; python_version < "3.5"
  Downloading http://mirrors.aliyun.com/pypi/packages/69/cb/f5be453359271714c01b9bd06126eaf2e368f1fddfff30818754b5ac2328/funcsigs-1.0.2-py2.py3-none-any.whl (17 kB)
Collecting futures; python_version == "2.7"
  Downloading http://mirrors.aliyun.com/pypi/packages/d8/a6/f46ae3f1da0cd4361c344888f59ec2f5785e69c872e175a748ef6071cdb5/futures-3.3.0-py2-none-any.whl (16 kB)
Requirement already satisfied: six>=1.4.0 in /usr/lib/python2.7/site-packages (from APScheduler==3.7.0) (1.9.0)
Collecting tzlocal~=2.0
  Downloading http://mirrors.aliyun.com/pypi/packages/5d/94/d47b0fd5988e6b7059de05720a646a2930920fff247a826f61674d436ba4/tzlocal-2.1-py2.py3-none-any.whl (16 kB)
Requirement already satisfied: pytz in /usr/lib/python2.7/site-packages (from APScheduler==3.7.0) (2016.10)
Installing collected packages: funcsigs, futures, tzlocal, APScheduler
Successfully installed APScheduler-3.7.0 funcsigs-1.0.2 futures-3.3.0 tzlocal-2.1

Python的版本不用说,现在主要分为Python2和Python3两大版本,而Python2是系统自带的版本,因此,以上安装是基于Python2安装,安装的前提需是需要安装pip包管理器。

apscheduler的几个简单示例:

interval触发器间隔调度,参数如下:

weeks (int) – 间隔几周 
days (int) – 间隔几天 
hours (int) – 间隔几小时 
minutes (int) – 间隔几分钟 
seconds (int) – 间隔多少秒 
start_date (datetime|str) – 开始日期 
end_date (datetime|str) – 结束日期 
timezone (datetime.tzinfo|str) – 时区 

cron触发器参数如下:

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 或者 mon,tue,wed,thu,fri,sat,sun) 
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) – 指定时区 

a,固定时间间隔执行有规律的任务(interval触发器):

使用apscheduler编排一个间隔任务,每两秒执行一次一个shell脚本,shell脚本内容为输出 hello  world~~!!,同时打印 一句话:当前时间+hello,apscheduler~~~!!!  ,因为apscheduler是一个库,因此,只需要导包,定义任务函数,然后执行所定义的函数即可,在这个示例中增加了一个shell脚本的调用,当然,这个是无限循环的,强制退出ctrl+c会报错,也就是说退出不够优雅,因此,实际的生产环境中应该添加try catch。为了更快的看到效果,因此设定任务时间为间隔两秒(实际生产中没有这么变态的计划~~~~)。

vim /root/test.sh

#!/bin/bash
#!author zsk
echo 'hello  world~~!!'

vim /root/apshceduler_test.py

# -*- coding: UTF-8 -*-
#coding=utf-8
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now+' hello,apscheduler~~~!!!')

if __name__=='__main__':
        scheduler.add_job(func, 'interval', seconds=2)
        while 1>0:
          scheduler.start()

使用这个Python文件的命令为: python  /root/apshceduler_test.py 即可。输出如下:

[root@centos8 ~]# python  /root/apshceduler_test.py
hello  world~~!!
2021-01-30 22:24:47 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:24:49 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:24:51 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:24:53 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:24:55 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:24:57 hello,apscheduler~~~!!!

b,crontab表达式定时任务

这个方式就是完全的crontab方式,请看下面示例(和上面的示例相比,多了一个导包,也就是下文的第三行,和定义任务的CronTrigger.from_crontab('* * * * *'),其余都是相似的,为了快速看到效果,定时为1分钟间隔)

,当然,这里的CronTrigger.from_crontab('* * * * *') 可以替换成任意的自定义的时间组合,就像crontab一样。

vim /root/apshceduler_test1.py

# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
from datetime import datetime
import subprocess,time

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now+" hello,apscheduler~~~!!!")

if __name__=='__main__':
        scheduler.add_job(func,CronTrigger.from_crontab('* * * * *'))
        while 1>0:
          scheduler.start()

python  /root/apshceduler_test1.py,输出结果为:

[root@centos8 ~]# python aa.py 
hello  world~~!!
2021-01-30 22:35:00 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:36:00 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:37:00 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:38:00 hello,apscheduler~~~!!!
hello  world~~!!
2021-01-30 22:39:00 hello,apscheduler~~~!!!

可以看到,时间确实是1分钟的间隔。

c,上面两个示例增加异常捕获,使得退出更为优雅,仍然使用间隔触发器interval。

#coding=utf-8
# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time,os

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now + ' hello apscheduler~~~!!!')

if __name__=='__main__':
        scheduler.add_job(func, 'interval', seconds=2)
        print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C    '))
        try:
            scheduler.start()
        except (KeyboardInterrupt, SystemExit):
            pass

d,前述示例修改触发器为cron,时间定在11点20:

#coding=utf-8
# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time,os

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now + ' hello apscheduler~~~!!!')

if __name__=='__main__':
        scheduler.add_job(func, 'cron', hour=11,minute=20)
        print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C    '))
        try:
            scheduler.start()
        except (KeyboardInterrupt, SystemExit):
            pass

e,时间定在每个周日的中午2点53分执行计划任务,这里需要注意,必须有结束时间,否则任务计划不会启动,这里使用的是day_of_week参数,例如:day_of_week='*'代表每一天,day_of_week='mon-sat'代表星期一到星期六,day_of_week='tue-thu'代表星期二到星期四。:

#coding=utf-8
# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time,os

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now + ' hello apscheduler~~~!!!')

if __name__=='__main__':
        scheduler.add_job(func, 'cron', day_of_week='sun', hour=14, minute=53,end_date='2021-12-31')
        print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C    '))
        try:
            scheduler.start()
        except (KeyboardInterrupt, SystemExit):
            pass

也可以这样设定,每个月的30和31号中午3点22执行任务。

#coding=utf-8
# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time,os

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now + ' hello apscheduler~~~!!!')

if __name__=='__main__':
        scheduler.add_job(func, 'cron', day='30,31', hour=15, minute=22,end_date='2021-12-12',id='myfirstjob')
        print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C    '))
        try:
            scheduler.start()
        except (KeyboardInterrupt, SystemExit):
            pass

f,多个定时任务,也就是多个Python函数,其中的一个任务直接调用Linux系统的命令并输出(Python函数内可多个命令作为函数主体,本例是ls -alh 和df -ah 两个命令,两种触发器,cron和interval):

#coding=utf-8
# -*- coding: UTF-8 -*-
#from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BlockingScheduler
from datetime import datetime
import subprocess,time,os

scheduler = BlockingScheduler()
#scheduler = BackgroundScheduler()


def func():
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    subprocess.call("/bin/bash /root/test.sh",shell=True)
    print(now + ' hello apscheduler~~~!!!')
def func1():
    subprocess.Popen("ls -alh",shell=True)
    subprocess.call("df -ah",shell=True)
if __name__=='__main__':
        scheduler.add_job(func, 'cron', day='30,31', hour=15, minute=22,end_date='2021-12-12',id='myfirstjob')
        scheduler.add_job(func1, 'interval',seconds=3 )
        print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C    '))
        try:
            scheduler.start()
        except (KeyboardInterrupt, SystemExit):
            pass

猜你喜欢

转载自blog.csdn.net/alwaysbefine/article/details/113442019