python异步实现定时任务和周期任务的方法
作者:狡猾的皮球 发布时间:2021-11-11 19:01:45
标签:python,异步,定时,周期,任务
一. 如何调用
def f1(arg1, arg2):
print('f1', arg1, arg2)
def f2(arg1):
print('f2', arg1)
def f3():
print('f3')
def f4():
print('周期任务', int(time.time()))
timer = TaskTimer()
# 把任务加入任务队列
timer.join_task(f1, [1, 2], timing=15.5) # 每天15:30执行
timer.join_task(f2, [3], timing=14) # 每天14:00执行
timer.join_task(f3, [], timing=15) # 每天15:00执行
timer.join_task(f4, [], interval=10) # 每10秒执行1次
# 开始执行(此时才会创建线程)
timer.start()
f1~f4是我们需要定时执行的函数。
首先创建TaskTimer对象(TaskTimer的代码在下面)。调用join_task函数,把需要执行的函数加入到任务队列。最后调用start,任务就开始执行了。
join_task参数:
fun:需要执行的函数
arg:fun的参数,如果没有就传一个空列表
interval:如果有此参数,说明任务是周期任务,单位为秒(注意interval最少5秒)
timing:如果有此参数,说明任务是定时任务,单位为时
注意:interval和timing只能选填1个
二. 源码
import datetime
import time
from threading import Thread
from time import sleep
class TaskTimer:
__instance = None
def __new__(cls, *args, **kwargs):
"""
单例模式
"""
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
def __init__(self):
if not hasattr(self, 'task_queue'):
setattr(self, 'task_queue', [])
if not hasattr(self, 'is_running'):
setattr(self, 'is_running', False)
def write_log(self, level, msg):
cur_time = datetime.datetime.now()
with open('./task.log', mode='a+', encoding='utf8') as file:
s = "[" + str(cur_time) + "][" + level + "] " + msg
print(s)
file.write(s + "\n")
def work(self):
"""
处理任务队列
"""
while True:
for task in self.task_queue:
if task['interval']:
self.cycle_task(task)
elif task['timing']:
self.timing_task(task)
sleep(5)
def cycle_task(self, task):
"""
周期任务
"""
if task['next_sec'] <= int(time.time()):
try:
task['fun'](*task['arg'])
self.write_log("正常", "周期任务:" + task['fun'].__name__ + " 已执行")
except Exception as e:
self.write_log("异常", "周期任务:" + task['fun'].__name__ + " 函数内部异常:" + str(e))
finally:
task['next_sec'] = int(time.time()) + task['interval']
def timing_task(self, task):
"""
定时任务
"""
# 今天已过秒数
today_sec = self.get_today_until_now()
# 到了第二天,就重置任务状态
if task['today'] != self.get_today():
task['today'] = self.get_today()
task['today_done'] = False
# 第一次执行
if task['first_work']:
if today_sec >= task['task_sec']:
task['today_done'] = True
task['first_work'] = False
else:
task['first_work'] = False
# 今天还没有执行
if not task['today_done']:
if today_sec >= task['task_sec']: # 到点了,开始执行任务
try:
task['fun'](*task['arg'])
self.write_log("正常", "定时任务:" + task['fun'].__name__ + " 已执行")
except Exception as e:
self.write_log("异常", "定时任务:" + task['fun'].__name__ + " 函数内部异常:" + str(e))
finally:
task['today_done'] = True
if task['first_work']:
task['first_work'] = False
def get_today_until_now(self):
"""
获取今天凌晨到现在的秒数
"""
i = datetime.datetime.now()
return i.hour * 3600 + i.minute * 60 + i.second
def get_today(self):
"""
获取今天的日期
"""
i = datetime.datetime.now()
return i.day
def join_task(self, fun, arg, interval=None, timing=None):
"""
interval和timing只能存在1个
:param fun: 你要调用的任务
:param arg: fun的参数
:param interval: 周期任务,单位秒
:param timing: 定时任务,取值:[0,24)
"""
# 参数校验
if (interval != None and timing != None) or (interval == None and timing == None):
raise Exception('interval和timing只能选填1个')
if timing and not 0 <= timing < 24:
raise Exception('timing的取值范围为[0,24)')
if interval and interval < 5:
raise Exception('interval最少为5')
# 封装一个task
task = {
'fun': fun,
'arg': arg,
'interval': interval,
'timing': timing,
}
# 封装周期或定时任务相应的参数
if timing:
task['task_sec'] = timing * 3600
task['today_done'] = False
task['first_work'] = True
task['today'] = self.get_today()
elif interval:
task['next_sec'] = int(time.time()) + interval
# 把task加入任务队列
self.task_queue.append(task)
self.write_log("正常", "新增任务:" + fun.__name__)
def start(self):
"""
开始执行任务
返回线程标识符
"""
if not self.is_running:
thread = Thread(target=self.work)
thread.start()
self.is_running = True
self.write_log("正常", "TaskTimer已开始运行!")
return thread.ident
self.write_log("警告", "TaskTimer已运行,请勿重复启动!")
来源:https://blog.csdn.net/qq_39687901/article/details/81985767


猜你喜欢
- 通过优化CSS代码,减小对系统资源的占用。自己整理出几个能减少系统资源占用的CSS写法,要优化网站的页面加载速度,这些注意点不能忽视!一、尽
- 众所周知,Jupyter notebook是一个交互式的Python shell,也就是IPython的封装版,非常适合用来进行数据分析和机
- 我正在开发一个档案管理系统,需要从数据库中同时调出图像及相关的文字说明,可我只做到了单纯地显示图片,像有一个数据库CHUNFENG,在数据库
- 一、实验目的:1.掌握Python中柱状图、条形图绘图函数的使用2.利用上述绘图函数实现数据可视化二、实验内容:1.练习python中柱状图
- 问题产生:今天在编写神经网络的Cluster作业时,需要根据根据数据标签用不同的颜色画出数据的分布情况,由此学习到了这种高效的方法。传统思路
- 前段时间,微信群有一个朋友问了下面这个问题,虽然很简单,但是觉得有必要和大家做一个知识分享。这个问题一共有两个需求:① 获取视频的文件大小;
- 我们都知道,可以使用高德地图api实现经纬度与地址的转换。那么,当我们有很多个地址与经纬度,需要批量转换的时候,应该怎么办呢?在这里,选用高
- 线性表 线性表是线性结构的抽象,线性结构的特点是结构中的数据元素之间存在一对一的线性关系。 数据元素之间的位置关系是一个接一个的排列: .除
- 本文介绍了Python字符串格式化,主要有两种方法,分享给大家,具体如下用于字符串的拼接,性能更优。字符串格式化有两种方式:百分号方式、fo
- 在cssrain整理的一个 试题集 中有这么一道题:<SCRIPT LANGUAGE="JavaScript"&g
- 一、将数据写入opengauss前提准备:成功opengauss数据库,并创建用户jack,创建数据库datasets。数据准备:所用数据以
- Python 3.8是Python语言的最新版本,它适合用于编写脚本、自动化以及机器学习和Web开发等各种任务。现在Python 3.8已经
- 本文实例讲述了php版银联支付接口开发的方法。分享给大家供大家参考,具体如下:支付接口现在有第三方的支付接口也有银行的支付接口。这里就来介绍
- 前言最近因为工作的需要,需要写个短链服务,用到了10->62进制,网上找了一个,可以转换最多76位进制的博客,现在分享出来,下面话不多
- 本文实例为大家分享了python webp图片格式转化的具体代码,供大家参考,具体内容如下1、将本地的webp图片转换为jpg2、将下载的w
- 古巴比伦王颁布了汉摩拉比法典,刻在黑色的玄武岩,距今已经三千七百多年,你在橱窗前…熟悉吧?没错,这就是周董的爱在西元前歌词。前不久工作不是很
- QSplitter使用户可以通过拖动子面板的边界控制子面板的大小。在我们的例子中,我们使用了两个QSplitter 对三个QFrame 控件
- 怎样压缩sql server2000的数据库备份文件,像rar一样?小弟有一7m的sql server2000 数据库备
- 在网站的一些应用中需要提供用户直接打印页面的功能,最明显的就是电子优惠券,商家根据网站提供的模板输入内容,然后生成优惠券页面,用户打印这个页
- 自今年1月份以Jetbrain公司严厉打击旗下开发工具产品(如:IntelliJ IDEA、WebStorm、PyCharm等)的盗版破解以