python中的轻量级定时任务调度库:schedule

摘要:
说到定时任务调度,我相信很多人会想到芹菜,或者写一个脚本并将其放到crontab中。因此,我找到了一个用于调度调度任务的轻量级库:schedule。库的安装也是最简单的管道安装计划,很容易理解。由于job1和job2的执行时间,任务被延迟。时间表库使用起来相对简单,不包含太多内容。
提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中。不过,一个小的定时脚本,要用celery的话太“重”了。所以,我找到了一个轻量级的定时任务调度的库:schedule。
schedule库是一个轻量级的定时任务方案,优势是使用简单,也不需要做什么配置;缺点是无法动态添加任务,也无法将任务持久化。
 
库的安装还是最简单的pip install schedule,使用起来也是很容易理解的。我们从最简单的栗子看起:
import schedule
import time
 
def job():
    print("I'm working...")
 
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every(5).to(10).days.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
 
while True:
    schedule.run_pending()
    time.sleep(1)
这是在pypi上面给出的示例。这个栗子简单到我不需要怎么解释。而且,通过这个栗子,我们也可以知道,schedule其实就只是个定时器。在while True死循环中,schedule.run_pending()是保持schedule一直运行,去查询上面那一堆的任务,在任务中,就可以设置不同的时间去运行。跟crontab是类似的。
 
但是,如果是多个任务运行的话,实际上它们是按照顺序从上往下挨个执行的。如果上面的任务比较复杂,会影响到下面任务的运行时间。比如我们这样:
import datetime
import schedule
import time
 
def job1():
    print("I'm working for job1")
    time.sleep(2)
    print("job1:", datetime.datetime.now())
 
def job2():
    print("I'm working for job2")
    time.sleep(2)
    print("job2:", datetime.datetime.now())
 
def run():
    schedule.every(10).seconds.do(job1)
    schedule.every(10).seconds.do(job2)
 
    while True:
        schedule.run_pending()
        time.sleep(1)
接下来你就会发现,两个定时任务并不是10秒运行一次,而是12秒。是的。由于job1和job2本身的执行时间,导致任务延迟了。
 
其实解决方法也很简单:用多线程/多进程。不要幼稚地问我“python中的多线程不是没有用吗?”这是两码事。开了一条线程,就把job独立出去运行了,不会占主进程的cpu时间,schedule并没有花掉执行一个任务的时间,它的开销只是开启一条线程的时间,所以,下一次执行就变成了10秒后而不是12秒后。
 
import datetime
import schedule
import threading
import time
 
def job1():
    print("I'm working for job1")
    time.sleep(2)
    print("job1:", datetime.datetime.now())
 
def job2():
    print("I'm working for job2")
    time.sleep(2)
    print("job2:", datetime.datetime.now())
 
def job1_task():
    threading.Thread(target=job1).start()
 
def job2_task():
    threading.Thread(target=job2).start()
 
def run():
    schedule.every(10).seconds.do(job1_task)
    schedule.every(10).seconds.do(job2_task)
 
    while True:
        schedule.run_pending()
        time.sleep(1)
就是这么简单。
 
唯一要注意的是,这里面job不应当是死循环类型的,也就是说,这个线程应该有一个执行完毕的出口。一是因为线程万一僵死,会是非常棘手的问题;二是下一次定时任务还会开启一个新的线程,执行次数多了就会演变成灾难。如果schedule的时间间隔设置得比job执行的时间短,一样会线程堆积形成灾难,所以,还是需要注意一下的。
 
schedule这个库使用起来比较简单,内容不是很多。我这里介绍的大概用法基本上够用了,还想了解其他特性的话,可以参考官网:https://schedule.readthedocs.io/en/stable/

免责声明:文章转载自《python中的轻量级定时任务调度库:schedule》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇记录POI导入时单元格下拉框两种实现方式(excel数据有效性)jquery插件:点击拉出的右侧滑动菜单下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Go语言的调度模型(GPM)

GPM模型 定义于src/runtime/runtime2.go G: Gourtines(携带任务), 每个Goroutine对应一个G结构体,G保存Goroutine的运行堆栈,即并发任务状态。G并非执行体,每个G需要绑定到P才能被调度执行。 P: Processors(分配任务), 对G来说,P相当于CPU核,G只有绑定到P(在P的local ru...

《Python》网络编程之客户端/服务端框架、套接字(socket)初使用

一、软件开发的机构 我们了解的涉及到两个程序之间通讯的应用大致可以分为两种: 第一种是应用类:QQ、微信、网盘等这一类是属于需要安装的桌面应用 第二种是web类:比如百度、知乎、博客园等使用浏览器访问就可以直接使用的应用 这些应用的本质其实都是两个程序之间的通讯,而这两个分类又对应了两个软件开发的架构 1、C/S架构 C/S即:Client与Server,...

RxJava入门

项目小版本上线,抽空简单学习了下久仰大名的RxJava 一、引入 个人觉得rxjava的特点: 强大灵活的事件流处理(多线程/多事件/复合对象) 强大灵活优雅简洁的异步 链式调用 可自动Lambda化   实现:RxJava 是通过一种扩展的观察者模式来实现的 类比 类比 实际 实际 职责 演讲者 Button (可)被订阅者 (同右)...

Spring boot中最大连接数、最大线程数与最大等待数在生产中的异常场景

在上周三下午时,客户、业务和测试人员同时反溃生产环境登录进入不了系统,我亲自测试时,第一次登录进去了,待退出后再登录时,复现了客户的问题,场景像是请求连接被拒绝了,分析后判断是spring boot的连接数使用完了,于是重启了服务,客户访问都恢复正常。虽然问题暂时解决了,但实质原因还无法确定。根据分析,判断是spring boot服务连接被拒绝,查看配置的...

面试官:Redis 单线程已经很快,为何 6.0要引入多线程?有啥优势?

作者:Java斗帝之路 链接:https://www.jianshu.com/p/ba2f082ff668 Redis作为一个基于内存的缓存系统,一直以高性能著称,因没有上下文切换以及无锁操作,即使在单线程处理情况下,读速度仍可达到11万次/s,写速度达到8.1万次/s。但是,单线程的设计也给Redis带来一些问题: 只能使用CPU一个核; 如果删除的键...

python中的收集参数

收集参数在函数定义时在参数前面多加一个*(星号),这个  *  可以将提供的所有值放到一个元组中! 当带*(星号)的参数位于所有参数的最后,则会收集余下参数的值。 当带*(星号)的参数不在所有的参数的末尾,调用参数时,后续参数需要用关键字指定。*(星号)是不会收集带关键字的参数的。 当我们想要收集带关键字的参数时,要怎么办呢? 这样我们就要用到 **...