一、BackgroundScheduler与BlockingScheduler
区别
apscheduler
库中的BackgroundScheduler
和BlockingScheduler
都是调度器类,用于在后台执行任务。它们之间的主要区别在于任务调度的方式以及对主线程的影响。
-
BackgroundScheduler
:BackgroundScheduler
是一个非阻塞的调度器,适用于在后台执行任务而不阻塞主线程。- 它会创建一个后台线程来执行任务,这样主线程可以继续执行其他操作。
BackgroundScheduler
需要手动启动调度器,并且需要调用start
方法来开始任务调度。- 一旦调度器启动,它将根据预定的时间表自动触发任务的执行。
-
BlockingScheduler
:BlockingScheduler
是一个阻塞的调度器,适用于在主线程中执行任务。- 它会在主线程中循环执行任务,直到调度器被关闭或程序退出。
BlockingScheduler
会阻塞主线程,因此在使用它时需要注意,确保没有其他重要的任务被阻塞。- 要启动调度器,只需调用
start
方法即可。它将按照预定的时间表开始执行任务,并阻塞主线程。
二、示例
python3.8示例
import os
import sys
import uuid
from datetime import datetime, timedelta
# 非阻塞调度器,适用于后台执行任务,不阻塞主进程
from apscheduler.events import EVENT_ALL
from apscheduler.schedulers.background import BackgroundScheduler
# 阻塞调度器,适用于在主线程中执行任务,会在主线程中循环执行任务
from apscheduler.schedulers.blocking import BlockingScheduler
"""
interval间隔执行,date定时执行,cron周期执行
"""
job_id = uuid.uuid4().hex
print(job_id)
# = = = = = = = = = = = = = = = = = = = = = 任务定义 = = = = = = = = = = = = = = = = = = = = =
def task1(params):
print(f'执行任务1。。。,参数:{params}')
def task2(params):
print(f'执行任务2。。。,参数:{params}')
def task3(params):
print(f'执行任务3。。。,参数:{params}')
def task4(params):
print(f'执行任务4。。。,参数:{params}')
def task5(params):
print(f'执行任务5。。。,参数:{params}')
def task6(params):
print(f'执行任务6。。。,参数:{params}')
def task8(params):
print(f'执行任务8。。。,参数:{params}')
# 故意抛出异常,因为除数不能为0
print(1 / 0)
# = = = = = = = = = = = = = = = = = = = = = 应用示例 = = = = = = = = = = = = = = = = = = = = =
def easy_use():
"""
简单使用
:return:
"""
# 实例化
sched = BlockingScheduler()
# sched = BackgroundScheduler()
# 1. 间隔5秒(间隔设定,周/天/时/分/秒weeks、days、hours、minutes、seconds)
"""
当 coalesce 设置为 True 时,如果任务的执行时间被错过(即到了该执行任务的时间,但由于前一个任 务实例仍在运行或其他原因导致任务未能及时启动),那么调度器将不会立即启动一个新的任务实例,而是会等待下一个触发时间点再执行。这样可以防止任务堆积和重复执行,确保在任务执行时间较长或调度器繁忙时,任务不会“堆积”起来。
"""
sched.add_job(task1, 'interval', seconds=5, args=['间隔5秒执行'], id=job_id, name="测试任务1", coalesce=True)
# 2. 固定时间执行,run_date参数:可以是date类型、datetime类型、文本类型
sched.add_job(task2, 'date', run_date=datetime(2023, 7, 26, 17, 13, 0), args=['到2023-7-26 17:13执行'])
sched.add_job(task3, 'date', run_date="2023-07-26 17:12:50", args=['到2023-07-26 17:12:00执行'])
# 3. 在起始时间内,间隔执行
sched.add_job(task4, 'interval', seconds=5, start_date="2023-07-26 17:16:50", end_date="2023-07-26 17:17:50" ,args=['起始时间内,间隔5秒执行'])
# 4. cron触发器
sched.add_job(task5, 'cron', second='0/5', args=['cron触发器,间隔5秒执行'])
sched.add_job(task6, 'cron', hour='11', minute='0', second='0', args=['每天固定一个时间11:00:00执行'])
# 5. 任务监听任务
sched.add_job(task8, args=['执行一次,会出错'], next_run_time=datetime.now() + timedelta(seconds=10), id='123456')
# 删除任务
# sched.remove_job(sched.get_job(job_id).id)
# 暂停任务
sched.pause_job(sched.get_job(job_id).id)
# 恢复任务
sched.resume_job(sched.get_job(job_id).id)
# 输出作业信息
sched.print_jobs()
# 获取任务列表
print(sched.get_jobs())
# 配置任务执行完成和任务错误的监听
scheduler.add_listener(err_listener, mask=EVENT_ALL)
sched.start()
print("注册结束")
def advanced():
"""
进阶,配置项
:return:
"""
# 导入线程池执行器
from apscheduler.executors.pool import ThreadPoolExecutor
# 导入sqlalchemy,使用MySQL数据库存储
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
# 导入阻塞调度器
from apscheduler.schedulers.blocking import BlockingScheduler
# 导入cron表达式触发器
from apscheduler.triggers.cron import CronTrigger
# 导入生成随机数模块
import random
# 创建定时任务执行函数
def task7(number):
print("开始执行任务,传入的随机数为%s" % number)
# 作业存储器配置 使用MySQL数据库存储
# job_stores = {
# 'default': {
# 'type': 'sqlalchemy',
# 'url': 'mysql://root:xxxx@127.0.0.1:3306/xxx?charset=utf8'
# }
# }
# 使用django的stores
# from django_apscheduler.jobstores import DjangoJobStore
# scheduler.add_jobstore(DjangoJobStore(), "default")
# 执行器配置 使用线程池执行器,最大10个线程
executors = {
'default': ThreadPoolExecutor(10),
}
# Job相关配置,更多选项参见官方文档
job_defaults = {
# 1. 设置这个目的是,比如由于某个原因导致某个任务积攒了很多次没有执行(比如有一个任务是1分钟跑一次,但是系统原因断了5分钟),
# 2. 如果 coalesce=True,那么下次恢复运行的时候,会只执行一次,而如果设置 coalesce=False,那么就不会合并,会5次全部执行,
# 3. 也可以在每个job,add时,传参添加,这是统一配置
'coalesce': False,
# 同一个任务同一时间最多只能有3个实例在运行。
# 比如一个10分钟的job,指定每分钟运行1次,如果max_instance=3,那么在第3~10分钟上,新的运行实例不会被执行,因为已经有3个实例在运行。
'max_instances': 3
}
# 1. 实例化调度器,关键字配置
scheduler = BlockingScheduler(
# jobstores=job_stores,
executors=executors,
job_defaults=job_defaults,
timezone='Asia/Shanghai' # 指定时区
)
config = {
# 作业存储器配置 使用MySQL数据库存储
'apscheduler.jobstores.default': {
'type': 'sqlalchemy',
'url': 'mysql://root:123.com@127.0.0.1:3306/job?charset=utf8'
},
# 执行器配置 使用线程池执行器,最大10个线程
'apscheduler.executors.default': {
'class': 'apscheduler.executors.pool:ThreadPoolExecutor',
'max_workers': '10'
},
# Job配置,为新任务关闭合并模式
'apscheduler.job_defaults.coalesce': 'false',
# Job配置,同一个任务同一时间最多只能有3个实例在运行
'apscheduler.job_defaults.max_instances': '3',
# Job配置,指定时区
'apscheduler.timezone': 'Asia/Shanghai',
}
# 2. 实例化调度器,字典配置
scheduler = BlockingScheduler(config)
# = = = = = = = = = = = = = = = = = = = = = 其他使用示例 = = = = = = = = = = = = = = = = = = = = =
def get_job_info():
"""
根据job_id,获取job信息
:return:
"""
sched = BackgroundScheduler()
print(sched.get_job(job_id).name)
def err_listener(event):
job_id = str(event.job_id)
print(job_id)
print(event.exception)
# = = = = = = = = = = = = = = = = = = = = = 装饰器应用示例 = = = = = = = = = = = = = = = = = = = = =
# 装饰器,定时任务执行函数
scheduler = BlockingScheduler()
@scheduler.scheduled_job(trigger="interval", args=(1,), seconds=3)
def task7(number):
print("开始执行任务,传入的参数是%s" % number)
if __name__ == '__main__':
print("主进程...start...")
easy_use()
print("主进程...end...")