python:schedule库包

426 阅读10分钟

参考网址

www.cnblogs.com/longsongpon… www.yisu.com/zixun/69768…

前言

如果你想周期性(定时)的执行某个python脚本,最出名的就是crontab脚本,但是crontab具有以下的缺点:
    <1>不方便执行秒级别的任务
    <2>当需要执行的脚本多达数百个的时候,crontab的管理就会不方便。
    
python中有一个轻量级的定时任务调度的库包:schedule.
该库包可以完成每分钟,每小时,每天,周几,特定日期的定时任务。
schedule的一般语法是: 
   scedule.every(时间数).时间类型.do(job)

获取所有的任务:
    all_jobs = schedule.get_jobs()

取消所有的任务:
    schedule.clear()

比如
   # 每十分钟执行任务
   schedule.every(10).minutes.do(job)
   
   # 每个小时执行任务
   schedule.every().hour.do(job)
   
   # 每天的10:30执行任务
   # 如果是每天执行任务的话,在every()括号中不填写参数,然后在.at()中填写一天中执行任务的具体时间
   schedule.every().day.at("10:30").do(job)
   
   # 每个周一执行任务
   schedule.every().monday.do(job)
   
   # 每个星期三的13:15分执行任务
   schedule.every().wednesday.at("13:15").do(job)
   
   # 每分钟的第17秒执行任务
   schedule.every().minute.at(":17").do(job)
   
   # 每个周一的12:40执行任务
   schedule.every().monday.at("12:40").do(job_1)
   
   # 每个周二的16:40执行任务
   schedule.every().tuesday.at("16:40").do(job_2)
   
   schedule.run_all()# 立即运行所有作业,每次作业间隔10秒schedule.run_all(delay_seconds=10)
   
   while True: 
       schedule.run_pending() 
       time.sleep(1)

设置任务截止时间(until)

如果你需要让某个作业到某个时间截止,你可以通过这个方法:
import schedule
from datetime import datetime, timedelta, time

def job():
    print('Boo')

# 每个小时运行作业,18:30后停止
schedule.every(1).hours.until("18:30").do(job)

# 每个小时运行作业,直到2030-01-01 18:33停止
schedule.every(1).hours.until("2030-01-01 18:33").do(job)

#每个小时运行作业,8个小时后停止
schedule.every(1).hours.until(timedelta(hours=8)).do(job)

# 每个小时运行作业,11:32:42后停止
schedule.every(1).hours.until(time(11, 33, 42)).do(job)

# 每个小时运行作业,2020-5-17 11:36:20后停止
schedule.every(1).hours.until(datetime(2020, 5, 17, 11, 36, 20)).do(job)

#截止日期之后,该作业将无法运行。

代码示例

<1>一般的运行方式


import schedule
import time

def job(name):
    print("her name is : ", name)

name = "longsongpong"

schedule.every(10).minutes.do(job, name)  # 每隔10分钟执行一次job这个函数,入参是name
schedule.every().hour.do(job, name)       # 每隔一小时执行一次任务
schedule.every().day.at("10:30").do(job, name)  # 每天的10:30执行一次任务
schedule.every(5).to(10).days.do(job, name)   # 每隔5到10天执行一次任务 
schedule.every().monday.do(job, name)    每周一的这个时候执行一次任务
schedule.every().wednesday.at("13:15").do(job, name)  每周三13:15执行一次任务

while True:
    schedule.run_pending()  #run_pending:运行所有可以运行的任务
    time.sleep(1)

# 切记
#schedule方法是串行的,也就是说,如果各个任务之间时间不冲突,那是没问题的;如果时间有冲突的话,会串行的执行命令

import schedule
import time
import threading

def job():
    print("I'm working... in job1  start")
    time.sleep(15)
    print("I'm working... in job1  end")

def job2():
    print("I'm working... in job2")

schedule.every(10).seconds.do(job)  # 如果要执行的函数没有入参数,则不用写
schedule.every(10).seconds.do(job2)

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

# 运行结果如下
I’m working… in job1 start 
I’m working… in job1 end 
I’m working… in job2
# 可以看出,任务是串行的

<2>多线程并发

import schedule
import time
import threading

def job():
    print("I'm working... in job1  start")
    time.sleep(15)
    print("I'm working... in job1  end")

def job2():
    print("I'm working... in job2")

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

 schedule.every(10).seconds.do(run_threaded,job)
 schedule.every(10).seconds.do(run_threaded,job2)


while True:
    schedule.run_pending()
    time.sleep(1)
    
# 输出结果
I'm working... in job1  start
I'm working... in job2
I'm working... in job1  start
I'm working... in job2
I'm working... in job1  end
I'm working... in job1  start
I'm working... in job2

run_pengding()和run_all()的区别

run_all()是立即执行任务,执行结束之后就完了,也就是说并不能起到周期性的作用。
run_pending()是严格等到了定时的时间再去执行任务,能起到周期性执行任务的作用。

run_all()和run_pending()可以一起使用。
import schedule
import time

def do_func(name,age):
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    schedule.every(3).seconds.do(do_func,"张三丰",100)

    while True:
        schedule.run_pending()

if __name__=="__main__":
    main()
    
#执行结果如下,即启动任务后,过一个时间间隔才执行

2022-05-25 01:43:04
2022-05-25 01:43:07 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:43:10 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:43:13 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:43:16 in do func : 姓名:张三丰 年龄:100
可以看到:
   定时任务是每3秒执行一次,
   我是2022-05-25 01:43:04启动任务的,可以看到是到了2022-05-25 01:43:07才开执行的,也就是过了一个时间间隔之后才执行的。
   
import schedule
import time

def do_func(name,age):
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    schedule.every(3).seconds.do(do_func,"张三丰",100)
    schedule.run_all()

    while True:
        schedule.run_pending()

if __name__=="__main__":
    main()

#可以看出,此时任务立刻执行,不会等3秒再执行,立刻执行之后再开始按照定时任务设置的规则去执行

2022-05-25 01:46:17
2022-05-25 01:46:17 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:46:20 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:46:23 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:46:26 in do func : 姓名:张三丰 年龄:100
# 立刻执行可以设置延时,这里的延时是指延长这些时间之后,定时任务才生效

import schedule
import time

def do_func(name,age):
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    schedule.every(3).seconds.do(do_func,"张三丰",100)
    schedule.run_all(delay_seconds=10)

    while True:
        schedule.run_pending()

if __name__=="__main__":
    main()
    
# 执行结果如下,可以看出,按照这种方式设置,也是立刻执行,
# 只不过立刻执行之后,要过10秒之后定时任务才生效,这里需要特别注意,这里的延时不是说延长这么多时间才执行

2022-05-25 01:48:20
2022-05-25 01:48:20 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:48:30 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:48:33 in do func : 姓名:张三丰 年龄:100
2022-05-25 01:48:36 in do func : 姓名:张三丰 年龄:100

设置时间间隔随机数

在有一些场景下,为了模拟比较自然的情景,需要采用随机的时间间隔,这就派上用场了
如下代码,设置随机间隔从2秒到10秒之间取随机数
  
import schedule
import time

# 定了一个功能函数
def do_func(name,age):
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

// 主函数
def main():
   # 定义定时任务时直接打标签
   schedule.every(2).to(10).seconds.do(do_func,"张三丰",100).tag("demo1","demo2")

while True:
   schedule.run_pending()
   
if __name__=="__main__":
   main()
执行结果如下,可以看出,确实在随机时间间隔,有的是隔5秒,有的隔8秒,有的隔4秒
> 2022-05-25 01:02:45 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:02:50 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:02:53 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:02:59 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:01 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:05 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:08 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:13 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:17 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:03:22 in do func : 姓名:张三丰 年龄:100

设置定时任务执行到指定时间

也就是说:设置了定时任务,然后到某个时间之后就停止。
如下均为指定到固定时间,这里因为是固定时间,就不再演示执行的结果了
  
import schedule
from datetime import datetime, timedelta, time

def job():
    print('in job...')
    # 每小时执行一次,直到今天的 18:30为止
    schedule.every(1).hours.until("18:30").do(job)
    
    # 每小时执行一次,直到 2030-01-01 18:33为止
    schedule.every(1).hours.until("2030-01-01 18:33").do(job)
    
    # 在未来8小时内,每小时执行一次
    schedule.every(1).hours.until(timedelta(hours=8)).do(job)
    
    # 每小时执行一次,直到今天的 11:33:42
    schedule.every(1).hours.until(time(113342)).do(job)

    # 每小时执行一次,直到 2030-01-01 18:33:20 为止
    schedule.every(1).hours.until(datetime(203011183320)).do(job)

立刻执行所有的任务 ,不管他们是怎么设置的定时

<1>先看一下,不使用立刻执行所有的任务时:

import schedule
import time

def do_func(name,age):
   print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
   print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
   schedule.every(3).seconds.do(do_func,"张三丰",100)

   while True:
       schedule.run_pending()  # 定时执行任务
   
if __name__=="__main__":
   main()
   
# 执行结果如下,即启动任务后,过一个时间间隔才执行
> 2022-05-25 01:43:04  # 这是开始的时间,代码中打印出来的,可以看到是04秒
>
> 2022-05-25 01:43:07 in do func : 姓名:张三丰 年龄:100  # 隔3秒
>
> 2022-05-25 01:43:10 in do func : 姓名:张三丰 年龄:100  # 隔3秒
>
> 2022-05-25 01:43:13 in do func : 姓名:张三丰 年龄:100  # 隔3秒
>
> 2022-05-25 01:43:16 in do func : 姓名:张三丰 年龄:100  # 隔3秒

<2>设置立即执行


import schedule
import time

def do_func(name,age):
    print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    schedule.every(3).seconds.do(do_func,"张三丰",100)

    schedule.run_all()

    while True:
        schedule.run_pending()
    
if __name__=="__main__":
   main()
   
# 可以看出,此时任务立刻执行,不会等3秒再执行,立刻执行之后再开始按照定时任务设置的规则去执行
# 

> 2022-05-25 01:46:17
>
> 2022-05-25 01:46:17 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:46:20 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:46:23 in do func : 姓名:张三丰 年龄:100
>
> 2022-05-25 01:46:26 in do func : 姓名:张三丰 年龄:100

<3>立刻执行可以设置延时,这里的延时是指延长这些时间之后,定时任务run_pending()才生效

import schedule
import time

def do_func(name,age):
   print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+" in do func : 姓名:"+name+" 年龄:"+str(age))

def main():
   print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
   schedule.every(3).seconds.do(do_func,"张三丰",100)
   
   # 这句代码的作用是
   # 当run_all()命令执行完之后,等10秒,然后再周期性的执行定时任务。
   # 因为如果没有延迟,我们不知道run_all()多久会执行完毕,如果没有执行完毕,这个时候到了run_pending()的时间了,可能会导致一些问题。
   schedule.run_all(delay_seconds=10)
   
   while True:
      schedule.run_pending()

if __name__=="__main__":
   main()