python 定时器

news2024/11/16 2:59:05

需求

我想在某一时刻完成某个任务,需要一个定时计划
调研了几种方式都不是很理想. 参考,python实现定时任务的8种方式详解
选择使用 apscheduler 库吧

  1. APScheduler简介
    APScheduler是Python的一个定时任务框架,用于执行周期或者定时任务,该框架不仅可以添加、删除定时任务,还可以将任务存储到数据库中,实现任务的持久化,使用起来非常方便。
    APscheduler全称Advanced Python Scheduler,作用为在指定的时间规则执行指定的作业,其是基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务.
  2. 安装
    pip install apscheduler
  3. APScheduler组成
  • 触发器(trigger):包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行。除了他们自己初始配置以外,触发器完全是无状态的。
  • 作业存储(job store):存储被调度的作业,默认的作业存储是简单地把作业保存在内存中,其他的作业存储是将作业保存在数据库中。一个作业的数据将在保存在持久化作业存储时被序列化,并在加载时被反序列化。调度器不能分享同一个作业存储。
  • 执行器(executor):处理作业的运行,他们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。
  • 调度器(scheduler):其他的组成部分。通常在应用只有一个调度器,应用的开发者通常不会直接处理作业存储、调度器和触发器,相反,调度器提供了处理这些的合适的接口。配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。
    3.1 触发器(trigger)
    包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行。除了它们自己初始配置以外,触发器完全是无状态的。

APScheduler 有三种内建的 trigger:

date: 特定的时间点触发
interval: 固定时间间隔触发
cron: 在特定时间周期性地触发
后边我们写代码会看到
3.2 作业存储(job store)
如果你的应用在每次启动的时候都会重新创建作业,那么使用默认的作业存储器(MemoryJobStore)即可,但是如果你需要在调度器重启或者应用程序奔溃的情况下任然保留作业,你应该根据你的应用环境来选择具体的作业存储器。例如:使用Mongo或者SQLAlchemy JobStore (用于支持大多数RDBMS)。

    任务存储器是可以存储任务的地方,默认情况下任务保存在内存,也可将任务保存在各种数据库中。任务存储进去后,会进行序列化,然后也可以反序列化提取出来,继续执行。

3.3 执行器(executor)
Executor在scheduler中初始化,另外也可通过scheduler的add_executor动态添加Executor。

    每个executor都会绑定一个alias,这个作为唯一标识绑定到Job,在实际执行时会根据Job绑定的executor。找到实际的执行器对象,然后根据执行器对象执行Job。

    Executor的选择需要根据实际的scheduler来选择不同的执行器。

    处理作业的运行,它们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。

3.4 调度器(scheduler)
Scheduler是APScheduler的核心,所有相关组件通过其定义。scheduler启动之后,将开始按照配置的任务进行调度。除了依据所有定义Job的trigger生成的将要调度时间唤醒调度之外。当发生Job信息变更时也会触发调度。
scheduler可根据自身的需求选择不同的组件,如果是使用AsyncIO则选择AsyncIOScheduler,使用tornado则选择TornadoScheduler。
任务调度器是属于整个调度的总指挥官。它会合理安排作业存储器、执行器、触发器进行工作,并进行添加和删除任务等。调度器通常是只有一个的。开发人员很少直接操作触发器、存储器、执行器等。因为这些都由调度器自动来实现了。

4、常见的两种调度器
APScheduler中有很多种不同类型的调度器,BlockingScheduler与BackgroundScheduler是其中最常用的两种调度器。那他们之间有什么区别呢? 简单来说,区别主要在于BlockingScheduler会阻塞主线程的运行,而BackgroundScheduler不会阻塞。所以,在不同的情况下,选择不同的调度器:

BlockingScheduler: 调用start函数后会阻塞当前线程。当调度器是你应用中唯一要运行的东西时(如上例)使用。
BackgroundScheduler: 调用start后主线程不会阻塞。当你不运行任何其他框架时使用,并希望调度器在你应用的后台执行。

from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.schedulers.background import BackgroundScheduler

直接看代码

from apscheduler.schedulers.blocking import BlockingScheduler
import time
from datetime import datetime


# from apscheduler.schedulers.background import BackgroundScheduler

def my_task(scheduler):
    jobs = scheduler.get_jobs()
    print("my_task--", jobs)
    # 这里是你要执行的任务逻辑
    # with open('ab.txt','a+',encoding='utf8') as f:
    #     f.write('{}\n'.format(time.time()))


def task():
    now = datetime.now()
    ts = now.strftime("%Y-%m-%d %H:%M:%S")
    print(ts)


def task2():
    now = datetime.now()
    ts = now.strftime("%Y-%m-%d %H:%M:%S")
    print(ts + '666!')

    # 创建调度器BlockingScheduler()


scheduler = BlockingScheduler()
scheduler.add_job(task, 'date', run_date=datetime(2023, 10, 8, 14, 32, 50), id='test_job1')
scheduler.add_job(task2, 'date', run_date=datetime(2023, 10, 8, 14, 32, 40), id='test_job2')

# 添加定时任务
job = scheduler.add_job(my_task, 'interval', seconds=5, args=(scheduler,))
scheduler.start()
# 查看任务列表
# jobs = scheduler.get_jobs()
# print(jobs)


# 启动调度器
scheduler.start()
# 修改任务
job.modify(args=('hello', 'apscheduler'))

# 再次查看任务列表
jobs = scheduler.get_jobs()

print(jobs)

运行结果:
在这里插入图片描述
这里可以看到一个情况,就是一次性的任务,执行完,就从 scheduler 中踢除了

对于 add_job方法

    def add_job(self, func, trigger=None, args=None, kwargs=None, id=None, name=None,
                misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined,
                next_run_time=undefined, jobstore='default', executor='default',
                replace_existing=False, **trigger_args):
        """
        add_job(func, trigger=None, args=None, kwargs=None, id=None, \
            name=None, misfire_grace_time=undefined, coalesce=undefined, \
            max_instances=undefined, next_run_time=undefined, \
            jobstore='default', executor='default', \
            replace_existing=False, **trigger_args)

        Adds the given job to the job list and wakes up the scheduler if it's already running.

        Any option that defaults to ``undefined`` will be replaced with the corresponding default
        value when the job is scheduled (which happens when the scheduler is started, or
        immediately if the scheduler is already running).

        The ``func`` argument can be given either as a callable object or a textual reference in
        the ``package.module:some.object`` format, where the first half (separated by ``:``) is an
        importable module and the second half is a reference to the callable object, relative to
        the module.

        The ``trigger`` argument can either be:
          #. the alias name of the trigger (e.g. ``date``, ``interval`` or ``cron``), in which case
            any extra keyword arguments to this method are passed on to the trigger's constructor
          #. an instance of a trigger class

        :param func: callable (or a textual reference to one) to run at the given time
        :param str|apscheduler.triggers.base.BaseTrigger trigger: trigger that determines when
            ``func`` is called
        :param list|tuple args: list of positional arguments to call func with
        :param dict kwargs: dict of keyword arguments to call func with
        :param str|unicode id: explicit identifier for the job (for modifying it later)
        :param str|unicode name: textual description of the job
        :param int misfire_grace_time: seconds after the designated runtime that the job is still
            allowed to be run (or ``None`` to allow the job to run no matter how late it is)
        :param bool coalesce: run once instead of many times if the scheduler determines that the
            job should be run more than once in succession
        :param int max_instances: maximum number of concurrently running instances allowed for this
            job
        :param datetime next_run_time: when to first run the job, regardless of the trigger (pass
            ``None`` to add the job as paused)
        :param str|unicode jobstore: alias of the job store to store the job in
        :param str|unicode executor: alias of the executor to run the job with
        :param bool replace_existing: ``True`` to replace an existing job with the same ``id``
            (but retain the number of runs from the existing one)
        :rtype: Job

        """
        job_kwargs = {
            'trigger': self._create_trigger(trigger, trigger_args),
            'executor': executor,
            'func': func,
            'args': tuple(args) if args is not None else (),
            'kwargs': dict(kwargs) if kwargs is not None else {},
            'id': id,
            'name': name,
            'misfire_grace_time': misfire_grace_time,
            'coalesce': coalesce,
            'max_instances': max_instances,
            'next_run_time': next_run_time
        }
        job_kwargs = dict((key, value) for key, value in six.iteritems(job_kwargs) if
                          value is not undefined)
        job = Job(self, **job_kwargs)

        # Don't really add jobs to job stores before the scheduler is up and running
        with self._jobstores_lock:
            if self.state == STATE_STOPPED:
                self._pending_jobs.append((job, jobstore, replace_existing))
                self._logger.info('Adding job tentatively -- it will be properly scheduled when '
                                  'the scheduler starts')
            else:
                self._real_add_job(job, jobstore, replace_existing)

        return job
id:指定作业的唯一ID
name:指定作业的名字
trigger:apscheduler定义的触发器,用于确定Job的执行时间,根据设置的trigger规则,计算得到下次执行此job的时间, 满足时将会执行
executor:apscheduler定义的执行器,job创建时设置执行器的名字,根据字符串你名字到scheduler获取到执行此job的 执行器,执行job指定的函数
max_instances:执行此job的最大实例数,executor执行job时,根据job的id来计算执行次数,根据设置的最大实例数来确定是否可执行
next_run_time:Job下次的执行时间,创建Job时可以指定一个时间[datetime],不指定的话则默认根据trigger获取触发时间
misfire_grace_time:Job的延迟执行时间,例如Job的计划执行时间是21:00:00,但因服务重启或其他原因导致21:00:31才执行,如果设置此key为40,则该job会继续执行,否则将会丢弃此job
coalesce:Job是否合并执行,是一个bool值。例如scheduler停止20s后重启启动,而job的触发器设置为5s执行一次,因此此job错过了4个执行时间,如果设置为是,则会合并到一次执行,否则会逐个执行
func:Job执行的函数
args:Job执行函数需要的位置参数
kwargs:Job执行函数需要的关键字参数

触发器的三种

date: 特定的时间点触发
interval: 固定时间间隔触发
cron: 在特定时间周期性地触发

代码及参数

interval

在这里插入图片描述

scheduler = BlockingScheduler()
    scheduler.add_job(task, 'interval', seconds=3, id='test_job1')
    # 添加任务,时间间隔为5秒
    scheduler.add_job(task2, 'interval', seconds=5, id='test_job2')
    # 在2022-10-27 21:50:30和2022-10-27 21:51:30之间,时间间隔为6秒
    scheduler.add_job(task3, 'interval', seconds=6, start_date='2022-10-27 21:53:00', end_date='2022-10-27 21:53:30', id ='test_job3')
    # 每小时(上下浮动20秒区间内)运行task
    # jitter振动参数,给每次触发添加一个随机浮动秒数,一般适用于多服务器,避免同时运行造成服务拥堵。
    scheduler.add_job(task, 'interval', hours=1, jitter=20, id='test_job4')
    scheduler.start()

date

在这里插入图片描述
注意:run_date参数可以是date类型、datetime类型或文本类型。

	scheduler = BlockingScheduler()
    scheduler.add_job(task, 'date', run_date=datetime(2022, 10, 27, 21, 39, 00), id='test_job1')
    scheduler.add_job(task2, 'date', run_date=datetime(2022, 10, 27, 21, 39, 50), id='test_job2')
    scheduler.start()

cron

在这里插入图片描述
在这里插入图片描述

cron: 在特定时间周期性地触发,和Linux crontab格式兼容。它是功能最强大的触发器。

	scheduler = BlockingScheduler()
    # 在每年 1-3、7-9 月份中的每个星期一、二中的 00:00, 01:00, 02:00 和 03:00 执行 task 任务
    scheduler.add_job(task, 'cron', month='1-3,7-9', day_of_week='1-2', hour='0-3', id='test_job1')
    scheduler.start()

其他参考:apscheduler库用法详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1078522.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】二叉树遍历的实现(超详细解析,小白必看系列)

目录 一、前言 🍎为何使用链式二叉树 🍐何为链式二叉树 🍉二叉树的构建 💦创建二叉链结构 💦手动构建一颗树 🍓二叉树的遍历 (重点) 💦前序遍历 💦中…

二维码智慧门牌管理系统:提升小区管理的智能化水平

文章目录 前言一、二维码智慧门牌管理系统简介二、精准的门牌定位三、门牌编号优化三、更多特点四、未来展望 前言 随着科技的不断发展,智能化管理已经深入到我们生活的方方面面,而小区作为我们居住的重要场所,智能化管理更是必不可少。为了…

警惕!外贸常见的一些骗局!

随着网络技术和国际支付的普及,外贸汇款骗局也是时常发生,本文将列举外贸汇款骗局的常见套路和风险提示,以帮助广大外贸人更好地护好自己的“钱袋子”。 常见套路 1.钓鱼 出口商与买家的订单已经谈妥,把收款信息通过邮件发给买家…

【重拾C语言】七、指针(二)指针与数组(用指针标识数组、多维数组与指针、数组指针与指针数组)

目录 前言 七、指针 7.1~3 指针与变量、指针操作、指向指针的指针 7.4 指针与数组 7.4.1 用指针标识数组 7.4.2 应注意的问题 a. 数组名是指针常量 b. 指针变量的当前值 c. 数组超界 7.4.3 多维数组与指针 7.4.4 指针数组 a. 指针数组 b. 数组指针 c. 对比总结 前…

bash上下键选择选项demo脚本

效果如下: 废话不多说,上代码: #!/bin/bashoptions("111" "222" "333" "444") # 选项列表 options_index0 # 默认选中第一个选项 options_len${#options[]}echo "请用上下方向键进行选择&am…

【多线程案例】Java实现简单定时器(Timer)

1.定时器(Timer) 1.什么是定时器? 在日常生活中,如果我们想要在 t 时间 后去做一件重要的事情,那么为了防止忘记,我们就可以使用闹钟的计时器功能,它会在 t 时间后执行任务(响铃)提醒我们去执行这件事情. — 这就是J…

【数据结构-队列 二】【单调队列】滑动窗口最大值

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【单调队列】,使用【队列】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为&…

Springboot整合Druid:数据库密码加密的实现

ps:Springboot项目,为了防止某些人反编译看到yml里面的数据库密码,对密码进行加密处理,隐藏公钥形式。(总有人想扒掉你的底裤看看你屁股长什么样) 1.引入依赖(以前有依赖就不用了) 2.找到Druid…

你想知道的测试自动化-概览篇

测试自动化概念整理 协议 JSON Wire Protocol Specification JSON Wire 协议 现已过时的开源协议的端点和有效负载,它是W3C webdriver的先驱。 devtool协议 Chrome DevTools 协议允许使用工具来检测、检查、调试和分析 Chromium、Chrome 和其他基于 Blink 的浏…

轻松驾驭Hive数仓,数据分析从未如此简单!

1 前言 先通过SparkSession read API从分布式文件系统创建DataFrame 然后,创建临时表并使用SQL或直接使用DataFrame API,进行数据转换、过滤、聚合等操作 最后,再用SparkSession的write API把计算结果写回分布式文件系统 直接与文件系统交…

MyLife - Docker安装Redis

Docker安装Redis 个人觉得像reids之类的基础设施在线上环境直接物理机安装使用可能会好些。但是在开发测试环境用docker容器还是比较方便的。这里学习下docker安装redis使用。 1. Redis 镜像库地址 Redis 镜像库地址:https://hub.docker.com/_/redis/tags 这里是官方…

四向穿梭车智能机器人|HEGERLS托盘式四向穿梭车系统的换轨技术和故障恢复功能

随着物流行业的迅猛发展,托盘四向穿梭式立体库因其在流通仓储体系中所具有的高效密集存储功能优势、运作成本优势与系统化智能化管理优势,已发展为仓储物流的主流形式之一。托盘四向穿梭车立体仓库有全自动和半自动两种工作模式,大大提高了货…

java基础 异常

异常概述: try{ } catch{ }: package daysreplace;import com.sun.jdi.IntegerValue;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.…

pymoo包NSGA2算法实现多目标遗传算法调参详细说明

pymoo包NSGA2算法实现多目标遗传算法调参详细说明 1.定义待求解问题1.0定义问题的参数说明1.0.0 求解问题必须设置在def _evaluate(self, x, out, *args, **kwargs)函数中1.0.1 问题必须用 out["F"] [f1, f2] 包裹起来1.0.2 约束条件也必须用 out["G"] […

Oracle 简介与 Docker Compose部署

最近,我翻阅了在之前公司工作时的笔记,偶然发现了一些有关数据库的记录。当初,我们的项目一开始采用的是 Oracle 数据库,但随着项目需求的变化,我们不得不转向使用 SQL Server。值得一提的是,公司之前采用的…

Windows保姆级安装Docker教程

1.官网下载 2.安装 3.启动Hyper-V 4.检查是否安装成功 1.下载 1.1.打开官网,然后点击下载 官网链接:https://hub.docker.com/ 2.安装 下载好之后会得到一个exe程序,然后启动它,进行安装。 去掉 WSL 不使用Hyper-V&#xff0…

KdMapper扩展实现之REALiX(hwinfo64a.sys)

1.背景 KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称hwin…

使用testMe自动生成单元测试用例

文章目录 1、testMe简介2、插件对比2.1 testMe2.2 Squaretest2.3 Diffblue 3、IDEA插件安装4、单测用例4.1 maven依赖4.2 生成用例 5、自定义模板6、使用自定义模板生成用例7、调试用例 1、testMe简介 公司对于系统单元测试覆盖率有要求,需要达到50%或80%以上才可以…

RV1126-RV1109-进入uboot的按键和名字显示-HOSTNAME

今天添加一个小功能,就是uboot是按CTRLC进入的 今日我做了一个定制,让按L或者l让也进入uboot指令模式,并且修改主板名字显示 默认是CTRLC:键码值是0x03(ASCII对照表) 于是代码中跟踪: //rv1126_rv1109/u-boot/common/console.c int ctrlc(void) { #ifndef CONFIG_SANDBOXif (…

Python大数据之Python进阶(五)线程

文章目录 线程1. 线程的介绍2. 线程的概念3. 线程的作用4. 小结 线程 学习目标 能够知道线程的作用 1. 线程的介绍 在Python中,想要实现多任务除了使用进程,还可以使用线程来完成,线程是实现多任务的另外一种方式。 2. 线程的概念 线程是进程…