python APScheduler

时光毁灭记忆、已成空白 提交于 2020-02-12 07:20:18

简介

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

github:https://github.com/agronholm/apscheduler

官网文档:https://apscheduler.readthedocs.io/en/latest/

 

安装

1、pip安装

pip install apscheduler

2、源码安装

下载地址:https://pypi.python.org/pypi/APScheduler/

python setup.py install

 

组成

APScheduler整个系统可以说由这五个概念组成:

  • 触发器(trigger)包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行。除了他们自己初始配置意外,触发器完全是无状态的。
  • 作业存储(job store)存储被调度的作业,默认的作业存储是简单地把作业保存在内存中,其他的作业存储是将作业保存在数据库中。一个作业的数据讲在保存在持久化作业存储时被序列化,并在加载时被反序列化。调度器不能分享同一个作业存储。
  • 执行器(executor)处理作业的运行,他们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。
  • 调度器(scheduler)是其他的组成部分。你通常在应用只有一个调度器,应用的开发者通常不会直接处理作业存储、调度器和触发器,相反,调度器提供了处理这些的合适的接口。配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。
  • 任务(job):描述一个任务本身。

 

调度器(scheduler)的IO模型

scheduler由于IO模型的不同,可以有多种实现:

  • BlockingScheduler:main_loop就在当前进程的主线程内运行,所以调用start函数后会阻塞当前线程。通过一个threading.Event条件变量对象完成scheduler的定时唤醒。
  • BackgroundScheduler:和BlockingScheduler基本一样,除了main_loop放在了单独线程里,所以调用start后主线程不会阻塞
  • AsyncIOScheduler:使用asyncio作为IO模型的scheduler,和AsyncIOExecutor配合使用,用asynio中event_loop的call_later完成定时唤醒
  • GeventScheduler:和BlockingScheduler基本一样,使用gevent作为IO模型,和GeventExecutor配合使用
  • QtScheduler:使用QTimer完成定时唤醒
  • TornadoScheduler:使用tornado的IO模型,用ioloop.add_timeout完成定时唤醒
  • TwistedScheduler:配合TwistedExecutor,用reactor.callLater完成定时唤醒

1、BlockingScheduler简单应用:

from apscheduler.schedulers.blocking import BlockingScheduler
def my_job():
    print 'hello world'
 
scheduler = BlockingScheduler()
scheduler.add_job(my_job, 'interval', seconds=5)
scheduler.start()

上面的例子表示每隔5s执行一次my_job函数,输出hello world

2、BackgroundScheduler简单应用

from apscheduler.schedulers.background import BackgroundScheduler

def job3():
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
    print("I'm working job_3")

scheduler = BackgroundScheduler()
scheduler.add_job(job3, 'interval', seconds=3)  #间隔3秒钟执行一次
scheduler.start()

 

配置

import time
import redis
from pytz import utc
from pymongo import MongoClient
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.mongodb import MongoDBJobStore
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.events import EVENT_JOB_MAX_INSTANCES, EVENT_JOB_ERROR, EVENT_JOB_MISSED

client = MongoClient(host='127.0.0.1', port=27017)

pool = redis.ConnectionPool(host='127.0.0.1', port=16379)

jobstores = {
    'mongo': MongoDBJobStore(collection='job', database='test', client=client),
    'redis': RedisJobStore(connection_pool=pool),
    'default': MemoryJobStore(),
    'default_test': MemoryJobStore()
}

executors = {
    'default': ThreadPoolExecutor(200),
    'processpool': ProcessPoolExecutor(10)
}

job_defaults = {
    'coalesce': True,
    'max_instances': 1,
    'misfire_grace_time': 60
}

scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
  • coalesce:当由于某种原因导致某个job积攒了好几次没有实际运行(比如说系统挂了5分钟后恢复,有一个任务是每分钟跑一次的,按道理说这5分钟内本来是“计划”运行5次的,但实际没有执行),如果coalesce为True,下次这个job被submit给executor时,只会执行1次,也就是最后这次,如果为False,那么会执行5次(不一定,因为还有其他条件,看后面misfire_grace_time的解释)
  • max_instance: 就是说同一个job同一时间最多有几个实例再跑,比如一个耗时10分钟的job,被指定每分钟运行1次,如果我们max_instance值为5,那么在第6~10分钟上,新的运行实例不会被执行,因为已经有5个实例在跑了。默认情况下同一个job,只允许一个job实例运行。这在某个job在下次运行时间到达之后仍未执行完毕时,能达到控制的目的。你也可以该变这一行为,在你调用add_job时可以传递max_instances=5来运行同时运行同一个job的5个job实例。
  • misfire_grace_time:设想和上述coalesce类似的场景,如果一个job本来14:00有一次执行,但是由于某种原因没有被调度上,现在14:01了,这个14:00的运行实例被提交时,会检查它预订运行的时间和当下时间的差值(这里是1分钟),大于我们设置的30秒限制,那么这个运行实例不会被执行。
  • executor的选择:线程池和进程池。默认default是线程池方式。这个数是执行任务的实际并发数,如果你设置的小了而job添加的比较多,可能出现丢失调度的情况。同时对于python多线程场景,如果是计算密集型任务,实际的并发度达不到配置的数量。所以这个数字要根据具体的要求设置。

 

作业存储(job store)backend

jobstore提供给scheduler一个序列化jobs的统一抽象,提供对scheduler中job的增删改查接口,根据存储backend的不同,分以下几种

  • MemoryJobStore:没有序列化,jobs就存在内存里,增删改查也都是在内存中操作
  • SQLAlchemyJobStore:所有sqlalchemy支持的数据库都可以做为backend,增删改查操作转化为对应backend的sql语句
  • MongoDBJobStore:用mongodb作backend
  • RedisJobStore: 用redis作backend
  • ZooKeeperJobStore:用ZooKeeper做backend

 

触发器(trigger)控制

1、interval 间隔调度(每隔多久执行)

weeks (int) – number of weeks to wait
days (int) – number of days to wait
hours (int) – number of hours to wait
minutes (int) – number of minutes to wait
seconds (int) – number of seconds to wait
start_date (datetime|str) – starting point for the interval calculation
end_date (datetime|str) – latest possible date/time to trigger on
timezone (datetime.tzinfo|str) – time zone to use for the date/time calculations

例子:

#表示每隔3天17时19分07秒执行一次任务
sched.add_job(my_job, 'interval', days=03, hours=17, minutes=19, seconds=07)
#间隔3秒钟执行一次
scheduler.add_job(job3, 'interval', seconds=3)

 

2、date 定时调度(作业只会执行一次)

run_date (datetime|str) – the date/time to run the job at  -(任务开始的时间)
timezone (datetime.tzinfo|str) – time zone for run_date if it doesn’t have one already

例子:

#在指定的时间,只执行一次
scheduler.add_job(tick, 'date', run_date='2016-02-14 15:01:05')  
# The job will be executed on November 6th, 2009
sched.add_job(my_job, 'date', run_date=date(2009, 11, 6), args=['text'])
# The job will be executed on November 6th, 2009 at 16:30:05
sched.add_job(my_job, 'date', run_date=datetime(2009, 11, 6, 16, 30, 5), args=['text'])

 

3、cron定时调度(某一定时时刻执行)

(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) -(表示时区取值)

参数的取值格式:

例子:

#表示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')

 

操作

http://apscheduler.readthedocs.io/en/3.0/modules/schedulers/base.html#apscheduler.schedulers.base.BaseScheduler

 

参考:https://www.cnblogs.com/yueerwanwan0204/p/5480870.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!