Python使用apscheduler实现定时任务功能

发布时间:2022-5-25 09:41

之前一直使用schedule定时任务,而随着业务的不断变化,我发现在业务中schedule在满足业务上有一些吃力,一部分是我用的异步代码较多,而且时间要求上很灵活。用achedule多了,管理较为困难。这时就发现了一个更加灵活的库APScheduler其实严格意义上来说已经是一个完整的框架了。在某些场景下,比celery好用(我说的)。

安装

pip install apscheduler

使用

先看一个最简单的案例,每5秒执行函数一次

from apscheduler.schedulers.asyncio import AsyncIOScheduler
import asyncio
import os
import datetime

async def run():
    print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]执行一次")


if __name__ == '__main__':
    executor = AsyncIOScheduler(
        timezone='Asia/Shanghai',
        job_defaults={
            "misfire_grace_time": 3600,  # 允许存在多久时间的任务数
            "max_instances": 200,  # 该定时任务允许最大的实例个数
            "coalesce": False  # 多个任务堆积,是否运行最新的
        }
    )

    executor.add_job(
        run,
        trigger='interval',
        seconds=5,
        coalesce=False,
        misfire_grace_time=3600,
        args=[])

    executor.start()
    print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]线程开始执行")
    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        pass

虽然对于第一次接触的同学看着可能不是很明白,但是其实还是很简单的。整体分为3部分。

  • executor = AsyncIOScheduler()创建异步任务
  • executor.add_job()、executor.start()添加任务/启动任务
  • asyncio.get_event_loop().run_forever()写入循环任务开始

这里有一个问题要先说一下,就是因为apscheduler是一个功能强大且完善的定时任务框架,而且涉及了5大部分,分别是触发器(trigger)、作业存储(job store)、执行器(executor)、调度器(scheduler)、任务或作业(task)。

我目前也并没有一个项目是完整用到5个模块的。所以我主要还是说我用到的地方,别的地方我会先写上,以后我用到的话,会回来在补充上。

触发器(tigger)

这部分比较简单,APScheduler有三种自带的tigger,基本满足各种刁钻的业务要求了。

  • interval: 固定时间间隔触发
  • date: 特定的时间点触发(作业只会执行一次
  • cron: 在特定时间周期性地触发(量化常用)
executor.add_job(
    run,
    trigger='interval',
    seconds=5,
)

executor.add_job(
    run,
    trigger='corn',
    minute='*/5',
)

executor.add_job(
    run, 
    trigger='cron', 
    year="*", month="*", day="*", hour="15", minute="07", second="00"
)

执行器(executor)

  • BlockingScheduler 阻塞式调度器,适用于只跑调度器的程序
  • BackgroundScheduler后台式调度器,适用于非阻塞的情况,调度器会在后台运行
  • AsyncIOScheduler 我目前比较常用的,可以适用于async任务
  • TornadoSchedulerTornado调度器,还没用过
  • TwistedSchedulerTwisted调度器,还没用过
  • QtSchedulerQt调度器,还没用过

调度器(scheduler)

我在业务中暂时还没有用到,引用网上的说明,有机会尝试后我会在来完善

配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。 调度器主要用到阻塞和后台运行这2种 BlockingScheduler:main_loop就在当前进程的主线程内运行,所以调用start函数后会阻塞当前线程。通过一个threading.Event条件变量对象完成scheduler的定时唤醒。 BackgroundScheduler:和BlockingScheduler基本一样,除了main_loop放在了单独线程里,所以调用start后主线程不会阻塞

任务或作业(task)

目前只是用到add_job添加任务,其余的暂时还没用过。

补充

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    (datime|str)    最早开始日期(包含)
end_date    (datetime|str)    最晚结束日期(包含)
timezone    (datetime.tzinfo|str)    指定时区

interval触发器的参数如下

# 参数 类型  说明
weeks   int 间隔几周
days    int 间隔几天
houres  int 间隔几小时
minutes int 间隔几分钟
seconds int 间隔几秒钟
start_date  datetime/str    开始日期
end_time    datetime/str    结束日期
timezone    dateime.tzinfo/str  时区
python实现将list拼接为一个字符串 生活杂谈

python实现将list拼接为一个字符串

在 python 中如果想将 list 拼接为一个字符串,可使用 join() 方法。 join() 方法描述 将序列(列表或元组)中的元素以指定的字符连接成一个新的字符串。 语法 s...
Python如何截取字符函数 生活杂谈

Python如何截取字符函数

在工作中我们经常会遇到某种情况需要截取字符串中某个特定标签之间的内容(爬虫可能用到的较多),适用于很多情况例如字符串形式的xml报文、json格式的字符串以及其它类型的字符串。 因为我总...
Python实现自动填写脚本流程详解 生活杂谈

Python实现自动填写脚本流程详解

这篇文章主要介绍了Python实现自动填写脚本,100%准确率,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下! 前言 环境使用 Python 3.8 Pycharm 模...