Python中定时任务框架APScheduler的快速入门指南


Posted in Python onJuly 06, 2017

前言

大家应该都知道在编程语言中,定时任务是常用的一种调度形式,在Python中也涌现了非常多的调度模块,本文将简要介绍APScheduler的基本使用方法。

一、APScheduler介绍

APScheduler是基于Quartz的一个python定时任务框架,实现了Quartz的所有功能,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务。

APScheduler提供了多种不同的调度器,方便开发者根据自己的实际需要进行使用;同时也提供了不同的存储机制,可以方便与Redis,数据库等第三方的外部持久化机制进行协同工作,总之功能非常强大和易用。

在Python的世界中,另外一个齐名的调度模块是Celery,功能也非常的强大,号称分布式的调度器,感兴趣的读者可以自行进行研究。

官网文档地址:http://apscheduler.readthedocs.io/en/latest/

安装包位置: https://pypi.python.org/pypi/APScheduler/

在系统中,如何进行安装呢?其实非常简单,基于pip直接安装即可: 

pip install APScheduler

二、APScheduler的主要的调度类

在APScheduler中有以下几个非常重要的概念,需要大家理解:   

1、触发器(trigger)

包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行,根据trigger中定义的时间点,频率,时间区间等等参数设置。除了他们自己初始配置以外,触发器完全是无状态的。

2、作业存储(job store)

存储被调度的作业,默认的作业存储是简单地把作业保存在内存中,其他的作业存储是将作业保存在数据库中。一个作业的数据讲在保存在持久化作业存储时被序列化,并在加载时被反序列化。调度器不能分享同一个作业存储。job store支持主流的存储机制:redis, mongodb, 关系型数据库, 内存等等

3、执行器(executor)

处理作业的运行,他们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。基于池化的操作,可以针对不同类型的作业任务,更为高效地使用cpu的计算资源。
调度器(scheduler)

通常在应用只有一个调度器,调度器提供了处理这些的合适的接口。配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。

这里简单列一下常用的若干调度器:

  • BlockingScheduler:仅可用在当前你的进程之内,与当前的进行共享计算资源
  • BackgroundScheduler: 在后台运行调度,不影响当前的系统计算运行
  • AsyncIOScheduler: 如果当前系统中使用了async module,则需要使用异步的调度器
  • GeventScheduler: 如果使用了gevent,则需要使用该调度
  • TornadoScheduler: 如果使用了Tornado, 则使用当前的调度器
  • TwistedScheduler:Twister应用的调度器
  • QtScheduler: Qt的调度器

由此可知,在APscheduler的调度器中,是与底层的实现机制紧密相关的,需要依据当前的计算模型来动态选择调度器。

三、APScheduler的job管理

Job是APScheduler中的核心,其承接目前需要执行的工作和任务,其可以在系统运行过程中动态地进行增加/修改/删除/查询等操作。

3.1 Job的新增

共有两种方式进行新增job的操作:

基于add_job来动态增加

代码示例:

sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour='0-9', minute="*", second="*/4")

基于修饰器scheduled_job来动态装饰job的实际函数

代码示例:

@sched.scheduled_job('cron', id='my_job_id', day='last sun') 
def some_decorated_task(): 
 print("I am printed at 00:00:00 on the last Sunday of every month!")

3.2 移除作业

job = scheduler.add_job(myfunc, 'interval', minutes=2) 
job.remove() 
Same, using an explicit job ID: 
 
scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id') 
scheduler.remove_job('my_job_id')

基于job id来动态移除特定的job.

3.3 暂停和恢复作业

暂停作业:

  ? apscheduler.job.Job.pause()

  ? apscheduler.schedulers.base.BaseScheduler.pause_job()

恢复作业:

  ? apscheduler.job.Job.resume()

  ? apscheduler.schedulers.base.BaseScheduler.resume_job()

3.4. 获得job列表

获得调度作业的列表,可以使用 get_jobs() 来完成,它会返回所有的job实例。或者使用 print_jobs() 来输出所有格式化的作业列表。

3.5. 修改作业 job

可以通过apscheduler.job.Job.modify() or modify_job()来动态修改job的属性信息,除了job id无法修改之外,都是可以修改的。

job.modify(max_instances=6, name='Alternate name')

另外我们也可以通过apscheduler.job.Job.reschedule() or reschedule_job()动态重新设置trigger,示例如下:

scheduler.reschedule_job('my_job_id', trigger='cron', minute='*/5')

 3.6. 关闭调度器

默认情况下调度器会等待所有正在运行的作业完成后,关闭所有的调度器和作业存储。如果你不想等待,可以将wait选项设置为False。

scheduler.shutdown() 
scheduler.shutdown(wait=False)

四、 APScheduler的代码示例

这里使用装饰器来展示一个调度的使用:

from apscheduler.schedulers.blocking import BlockingScheduler 
 
sched = BlockingScheduler() 
 
@sched.scheduled_job('interval', seconds=3) 
def timed_job(): 
 print('This job is run every three minutes.') 
 
@sched.scheduled_job('cron', day_of_week='mon-fri', hour='0-9', minute='30-59', second='*/3') 
def scheduled_job(): 
 print('This job is run every weekday at 5pm.') 
 
print('before the start funciton') 
sched.start() 
print("let us figure out the situation")

代码说明:

在这段代码中,使用了当前进程中共享计算资源的BlockingScheduler,共使用了2个调度器,其中一个是间隔3秒的执行。

另外一个调度器是模仿cron来执行的,在周一到周五其间,每天的0点到9点直接,在30分到59分之间执行,执行频次为3秒。

基于正常代码的示例如下:

from apscheduler.schedulers.background import BackgroundScheduler 
from apscheduler.schedulers.blocking import BlockingScheduler 
 
import datetime 
import time 
import logging 
 
def job_function(): 
 print "Hello World" + " " + str(datetime.datetime.now()) 
 
if __name__ == '__main__': 
 log = logging.getLogger('apscheduler.executors.default') 
 log.setLevel(logging.INFO) # DEBUG 
 
 fmt = logging.Formatter('%(levelname)s:%(name)s:%(message)s') 
 h = logging.StreamHandler() 
 h.setFormatter(fmt) 
 log.addHandler(h) 
 
 print('start to do it') 
 
 sched = BlockingScheduler() 
 
 # Schedules job_function to be run on the third Friday 
 # of June, July, August, November and December at 00:00, 01:00, 02:00 and 03:00 
 sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour='0-9', minute="*", second="*/4") 
 
 sched.start()

五、某个异常问题的思考

在执行以下代码之时候,定时任务一直未能正常生效:

from apscheduler.schedulers.background import BackgroundScheduler 
from apscheduler.schedulers.blocking import BlockingScheduler 
 
import datetime 
import time 
 
def job_function(): 
 print "Hello World" + " " + str(datetime.datetime.now()) 
 
if __name__ == '__main__': 
 print('start to do it') 
 sched = BlockingScheduler() 
 sched.add_job(job_function, 'cron', day_of_week='mon-fri', hour='0-9', minute="*", second="*/4") 
 sched.start()

代码报错的错误信息为:

No handlers could be found for logger “apscheduler.scheduler”

从字面意思来分析,是没有logging模块的logger存在,故需要添加上去即可。

新增对应的logging信息即可:

import logging
log = logging.getLogger('apscheduler.executors.default') 
 log.setLevel(logging.INFO) # DEBUG 
 
 fmt = logging.Formatter('%(levelname)s:%(name)s:%(message)s') 
 h = logging.StreamHandler() 
 h.setFormatter(fmt) 
 log.addHandler(h)

后来笔者重新做了一次执行,即使移除掉logging的内容,依然可以正常执行,故可以推测为需要动态引入一次依赖包logging即可。

六、总结

APScheduler是一个非常强大易用的类库,为了我们简单快捷的解决问题提供了很多的工具,并且提供了很多灵活的扩展点,只要你添加若干的web页面,就可以创建一个强大的任务调度系统,不是吗?

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python机器学习之神经网络(一)
Dec 20 Python
python正则表达式及使用正则表达式的例子
Jan 22 Python
用python生成1000个txt文件的方法
Oct 25 Python
python3 tkinter实现点击一个按钮跳出另一个窗口的方法
Jun 13 Python
python join方法使用详解
Jul 30 Python
python在不同条件下的输入与输出
Feb 13 Python
python对数组进行排序,并输出排序后对应的索引值方式
Feb 28 Python
Tensorflow中的图(tf.Graph)和会话(tf.Session)的实现
Apr 22 Python
python 实现 hive中类似 lateral view explode的功能示例
May 18 Python
如何快速理解python的垃圾回收机制
Sep 01 Python
Django限制API访问频率常用方法解析
Oct 12 Python
Python getsizeof()和getsize()区分详解
Nov 20 Python
Python如何快速实现分布式任务
Jul 06 #Python
Python3下错误AttributeError: ‘dict’ object has no attribute’iteritems‘的分析与解决
Jul 06 #Python
Python标准库sched模块使用指南
Jul 06 #Python
用virtualenv建立多个Python独立虚拟开发环境
Jul 06 #Python
基于Python的关键字监控及告警
Jul 06 #Python
Python中装饰器兼容加括号和不加括号的写法详解
Jul 05 #Python
利用python模拟sql语句对员工表格进行增删改查
Jul 05 #Python
You might like
php MsSql server时遇到的中文编码问题
2009/06/11 PHP
浅析HTTP消息头网页缓存控制以及header常用指令介绍
2013/06/28 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
2016/01/09 PHP
js弹出层之1:JQuery.Boxy (二)
2011/10/06 Javascript
javascript开发随笔二 动态加载js和文件
2011/11/25 Javascript
JS实现很酷的水波文字特效实例
2015/02/26 Javascript
JavaScript获取网页表单提交方式的方法
2015/04/02 Javascript
javascript处理a标签超链接默认事件的方法
2015/06/29 Javascript
jquery实现仿JqueryUi可拖动的DIV实例
2015/07/31 Javascript
JavaScript reduce和reduceRight详解
2016/10/24 Javascript
常用的js方法合集
2017/03/10 Javascript
Vue仿手机qq的实例代码(demo)
2017/09/08 Javascript
JavaScript中严格判断NaN的方法
2018/02/16 Javascript
vue中的watch监听数据变化及watch中各属性的详解
2018/09/11 Javascript
ES6中Symbol、Set和Map用法详解
2019/08/20 Javascript
js判断一个对象是数组(函数)的方法实例
2019/12/19 Javascript
JS实现简易贪吃蛇游戏
2020/08/24 Javascript
python计算圆周长、面积、球体体积并画出圆
2014/04/08 Python
python中元类用法实例
2014/10/10 Python
python通过pil模块将raw图片转换成png图片的方法
2015/03/16 Python
pygame 精灵的行走及二段跳的实现方法(必看篇)
2017/07/10 Python
python基础练习之几个简单的游戏
2017/11/10 Python
linecache模块加载和缓存文件内容详解
2018/01/11 Python
在Python中定义一个常量的方法
2018/11/10 Python
python实现将汉字保存成文本的方法
2018/11/16 Python
Python OpenCV对本地视频文件进行分帧保存的实例
2019/01/08 Python
python如何实现视频转代码视频
2019/06/17 Python
python hashlib加密实现代码
2019/10/17 Python
python  logging日志打印过程解析
2019/10/22 Python
Python3爬虫中Splash的知识总结
2020/07/10 Python
Python爬虫入门教程01之爬取豆瓣Top电影
2021/01/24 Python
CSS3实现同时执行倾斜和旋转的动画效果
2016/10/27 HTML / CSS
阿姆斯特丹杜莎夫人蜡像馆官方网站:Madame Tussauds Amsterdam
2019/03/12 全球购物
纪检干部现实表现材料
2014/08/21 职场文书
2014年科室工作总结
2014/11/20 职场文书
2014年政协工作总结
2014/12/09 职场文书