python自动化之定时任务

1,071 阅读3分钟

在工作中,我们时常会碰到需要周期性执行的任务。这里特地对自动化实现定时任务的方式做了归纳整理。特此说明,该篇文章只整理了定时任务的python实现方式。

1. 利用while True + time.sleep()实现定时任务

time模块中的sleep(secs)函数,可以使得当前的线程暂停等待secs秒之后再继续执行。简而言之,就是当前的线程进入阻塞状态,等待secs秒之后,再由等待状态变为就绪状态,等待系CPU进行调度

基于该函数的特点,我们可以通过while True + time.sleep()的方式实现简单的定时任务

具体代码如下:

import time
import datetime
​
​
def task_func():
    print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    print('这是一个输出打印字符的定时任务')
    print('*******')
​
​
def loop_monitor():
    while True:
        task_func()
        time.sleep(5)
​
​
if __name__ == '__main__':
    loop_monitor()

result:

image-20211031115902193.png

这个定时任务是每隔5秒钟打印出7个*,并且打印出当前时间。

这种实现方式虽然简单高效,但是有其不足之处。主要缺点如下:

(1) 只能设置时间间隔,不能指定具体时间,比如每天21:00这种的就不行

(2) 这种方式是一个阻塞函数,也就是说sleep的这段时间内,程序啥也干不了。只能乖乖的等待

2. 利用threading.Timer实现定时任务

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

具体用法如下:

Timer(interval, function, args=[], kwargs={})

interval: 指定的时间

function: 要执行的方法

args/kwargs:要执行的方法的参数

具体代码如下:

import datetime
from threading import Timer
​
​
def time_printer():
    now = datetime.datetime.now()
    ts = now.strftime('%Y-%m-%d %H:%M:%S')
    print(f'this time {ts}')
    loop_monitor()
​
​
def loop_monitor():
    t = Timer(5, time_printer)
    t.start()
​
​
if __name__ == '__main__':
    loop_monitor()

result:

image-20211031155914691.png

3. 利用内置模块sched实现定时任务

sched模块实现了一个通用事件调度器,在调度器类使用了一个延迟函数等待特定的时间,执行任务。同时支持多线程应用程序,在每个任务执行后会立刻调用延时函数,以确保其他线程也能执行。

sched.scheduler(timefunc, delayfunc)这个类定义了调度事件的通用接口,他需要外部传入两个参数。timefunc是一个没有参数的返回时间类型数字的函数(经常使用time.time()),delayfunc是一个需要参数调用、与timefunc的输出兼容、作用为延迟多个时间单位的函数(常用的比如time.sleep())

具体代码如下:

import datetime
import time
import sched
​
​
def time_printer():
    now = datetime.datetime.now()
    ts = now.strftime('%Y-%m-%d %H:%M:%S')
    print(f'this time is {ts}')
    loop_monitor()
​
​
def loop_monitor():
    t = sched.scheduler(time.time, time.sleep)
    t.enter(5, 1, time_printer, ())
    t.run()
​
​
if __name__ == '__main__':
    loop_monitor()

result:

image-20211031164336756.png

scheduler对象主要方法:

enter(delay, priority, action, argument):安排一个时间来延迟delay个时间单位

cancel(event): 从队列中删除事件。如果事件不是当前队列中的事件,则该方法将跑出一个ValueError

run():运行所有预定的事件。这个函数先等待,然后执行事件,直到不再有预定的事件

4.利用APScheduler框架实现

APScheduler是定时任务框架,提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务。它主要有以下几个特点: (1) 类似于Linux/Cron的调度程序(可以选择开始和结束时间)

(2) 基于时间间隔的执行调度(周期性调度,可以选择开始和结束时间)

(3) 一次性执行任务(在设定的日期/时间运行一次任务)

具体代码如下:

from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
​
​
def task_job():
    print(f'定时任务在执行{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
​
​
if __name__ == '__main__':
    sched = BlockingScheduler()
    sched.add_job(task_job, 'interval', seconds=5, id='my_job_id')
    sched.start()

result:

image-20211101233321687.png

该框架可以指定具体时刻执行

sched.add_job(task_job, 'cron', month='10-12', day='3rd', hour='0-3')

意思是每年的10月3号和12月3号早上0点到3点执行该任务