Python定时任务—sched、timeloop、schedule、apscheduler等

内置库实现

下面例子中的时间间隔interval = 1,即每1s执行一次定时任务

1 while True + sleep

  • time.sleep方法可以实现令当前执行的线程暂停n秒后再继续执行。
  • 所谓暂停,即令当前线程进入阻塞状态,当达到sleep规定的时间后,再由阻塞状态转为就绪状态,等待 CPU 调度
  • 基于这样的特性可以通过while True + sleep的方式实现简单的定时任务
def demo01(interval):
    def method():
        print('[{} - {}] running...'.format(
            threading.current_thread().getName(),
            datetime.datetime.now().strftime('%H:%M:%S')
        ))

    while True:
        method()
        time.sleep(interval)

Python定时任务—sched、timeloop、schedule、apscheduler等_第1张图片

2 threading.Timer

threading 模块中的Timer是一个非阻塞函数,比 sleep 稍好一点,timer最基本理解就是定时器,
我们可以启动多个定时任务,这些定时器任务是异步执行,所以不存在等待顺序执行问题

import threading

def demo02(interval):
    def method():
        print('[{} - {}] running...'.format(
            threading.current_thread().getName(),
            datetime.datetime.now().strftime('%H:%M:%S')
        ))
        # Timer只能执行一次, 这里需要循环调用, 否则只能执行一次
        demo02(interval)

    # 若method有参, 则传入第三个元组参数
    threading.Timer(interval, method).start()

Python定时任务—sched、timeloop、schedule、apscheduler等_第2张图片

3 内置模块sched

  • sched模块实现了一个通用事件调度器,在调度器类使用一个延迟函数等待特定的时间,执行任务。
    同时支持多线程应用程序,在每个任务执行后会立刻调用延时函数,以确保其他线程也能执行。
  • class sched.scheduler(timefunc, delayfunc)这个类定义了调度事件的通用接口,
    它需要外部传入两个参数,timefunc是一个没有参数的返回时间类型数字的函数(常用使用的如time模块
    里面的time),delayfunc应该是一个需要一个参数来调用、与timefunc的输出兼容、并且作用为延迟
    多个时间单位的函数(常用的如time模块的sleep)
import sched

def demo03(interval):
    def method():
        print('[{} - {}] running...'.format(
            threading.current_thread().getName(),
            datetime.datetime.now().strftime('%H:%M:%S')
        ))
        # 也需要循环调用
        demo03(interval)

    # 生成调度器
    s = sched.scheduler(time.time, time.sleep)
    # s.enter(delay, priority, action, argument) 安排一个事件来延迟delay个时间单位
    s.enter(interval, 1, method, ())
    # 运行所有预定的事件, 该方法将等待(使用传递给构造函数的delayfunc()函数), 然后执行事件, 直到不再有预定的事件
    s.run()

Python定时任务—sched、timeloop、schedule、apscheduler等_第3张图片

timeloop库实现

import datetime
import threading
import timeloop

tl = timeloop.Timeloop()

@tl.job(interval=datetime.timedelta(seconds=2))
def job_every_2s():
    print('[{} - {}] 运行周期为2s的定时任务...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

@tl.job(interval=datetime.timedelta(seconds=5))
def job_every_5s():
    print('[{} - {}] 运行周期为5s的定时任务...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

@tl.job(interval=datetime.timedelta(seconds=10))
def job_every_10s():
    print('[{} - {}] 运行周期为10s的定时任务...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

if __name__ == '__main__':
    tl.start(job_every_2s)
    tl.start(job_every_5s)
    tl.start(job_every_10s)

Python定时任务—sched、timeloop、schedule、apscheduler等_第4张图片

schedule库实现

schedule是一个第三方轻量级的任务调度模块,可以按照秒,分,小时,日期或者自定义事件执行时间。

schedule允许用户使用简单、人性化的语法以预定的时间间隔定期运行Python函数(或其它可调用函数)。

基本使用

import datetime
import threading
import schedule

def job():
    print('[{} - {}] running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))


schedule.every().second.do(job)
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("12:34").do(job)
schedule.every(5).to(10).minutes.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第5张图片

@repeat装饰静态方法

import datetime
import threading
import time
import schedule

@schedule.repeat(schedule.every().second)
def job():
    print('[{} - {}] running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

while True:
    schedule.run_pending()
    time.sleep(1)

Python定时任务—sched、timeloop、schedule、apscheduler等_第6张图片

调用任务时传递参数

import datetime
import threading
import schedule

def job(name):
    print('[{} - {}] 你好: {}'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S'), name
    ))

schedule.every(2).seconds.do(job, name='Alice')
schedule.every(4).seconds.do(job, name='Bob')
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第7张图片

装饰器传递参数

import datetime
import threading
import schedule

@schedule.repeat(schedule.every().second, 'World')
@schedule.repeat(schedule.every(2).seconds, 'Mars')
def job(name):
    print('[{} - {}] 你好: {}'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S'), name
    ))

while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第8张图片

取消任务

import datetime
import threading
import schedule

i = 0

def some_task():
    global i
    i += 1
    print('[{} - {}] i = {}'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S'), i
    ))
    if i == 10:
        schedule.cancel_job(job)
        print('[{} - {}] 取消任务...'.format(
            threading.current_thread().getName(),
            datetime.datetime.now().strftime('%H:%M:%S')
        ))
        exit(1)

job = schedule.every().second.do(some_task)
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第9张图片

运行一次任务但不退出程序

import datetime
import threading
import schedule

def job_that_executes_once():
    print('[{} - {}] running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))
    return schedule.CancelJob

schedule.every(2).seconds.do(job_that_executes_once)
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第10张图片

根据标签检索任务

import datetime
import threading
import schedule

def job(name):
    print('[{} - {}] 你好: {}'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S'),
        name
    ))

schedule.every().day.do(job, 'Andrea').tag('daily-tasks', 'friend')
schedule.every().hour.do(job, 'John').tag('hourly-tasks', 'friend')
schedule.every().hour.do(job, 'Monica').tag('hourly-tasks', 'customer')
schedule.every().day.do(job, 'Derek').tag('daily-tasks', 'guest')
friends = schedule.get_jobs('friend')
print('[{} - {}] friends: {}'.format(
    threading.current_thread().getName(),
    datetime.datetime.now().strftime('%H:%M:%S'), friends
))

在这里插入图片描述

根据标签取消任务

import datetime
import threading
import schedule

def job(name):
    print('[{} - {}] 你好: {}'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S'),
        name
    ))
    if name == 'Cancel':
        schedule.clear('second-tasks')
        print('[{} - {}] 取消任务...'.format(
            threading.current_thread().getName(),
            datetime.datetime.now().strftime('%H:%M:%S')
        ))

schedule.every().second.do(job, 'Andrea').tag('second-tasks', 'friend')
schedule.every().second.do(job, 'John').tag('second-tasks', 'friend')
schedule.every().hour.do(job, 'Monica').tag('hourly-tasks', 'customer')
schedule.every(5).seconds.do(job, 'Cancel').tag('daily-tasks', 'guest')
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第11张图片

运行任务到某时间

import datetime
import threading
import schedule

def job():
    print('[{} - {}] running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

schedule.every().second.until('16:01').do(job)  # 今天16:01停止
schedule.every().second.until('2024-05-23 18:30').do(job)  # 2024-05-23 18:30停止
schedule.every().second.until(datetime.timedelta(hours=4)).do(job)  # 4小时后停止
schedule.every().second.until(datetime.time(16, 0, 59)).do(job)  # 今天16:00:59停止
schedule.every().second.until(datetime.datetime(2024, 5, 23, 18, 30, 0)).do(job)  # 2024-05-23 18:30停止
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第12张图片

马上运行所有任务

主要用于测试,一般不会在生产环境中使用

import datetime
import threading
import schedule

def job1():
    print('[{} - {}] job1 running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

def job2():
    print('[{} - {}] job2 running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

schedule.every().monday.at('12:40').do(job1)
schedule.every().tuesday.at('16:40').do(job2)
# 立刻执行
schedule.run_all()
print('=============')
schedule.run_all(delay_seconds=3)  # 任务间延迟3秒

Python定时任务—sched、timeloop、schedule、apscheduler等_第13张图片

并行运行

基于Python内置队列实现

import datetime
import threading
import schedule

def job1():
    print('[{} - {}] job1 running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

def job2():
    print('[{} - {}] job2 running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

def job3():
    print('[{} - {}] job3 running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

def run_threaded(job_func):
    job_thread = threading.Thread(target=job_func)
    job_thread.start()

schedule.every(2).seconds.do(run_threaded, job1)
schedule.every(2).seconds.do(run_threaded, job2)
schedule.every(2).seconds.do(run_threaded, job3)
while True:
    schedule.run_pending()

Python定时任务—sched、timeloop、schedule、apscheduler等_第14张图片

apscheduler框架实现

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

def job():
    print('[{} - {}] running...'.format(
        threading.current_thread().getName(),
        datetime.datetime.now().strftime('%H:%M:%S')
    ))

if __name__ == '__main__':
    sched = BlockingScheduler()
    sched.add_job(job, 'interval', seconds=1, id='my_job')
    sched.start()

Python定时任务—sched、timeloop、schedule、apscheduler等_第15张图片

参考链接

你可能感兴趣的:(Python,#,并发编程&定时任务,python)