python异步实现定时任务和周期任务的方法


Posted in Python onJune 29, 2019

一. 如何调用

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已运行,请勿重复启动!")

以上这篇python异步实现定时任务和周期任务的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
利用Python实现简单的相似图片搜索的教程
Apr 23 Python
Python ValueError: invalid literal for int() with base 10 实用解决方法
Jun 21 Python
Python基础教程之正则表达式基本语法以及re模块
Mar 25 Python
Python标准库sched模块使用指南
Jul 06 Python
浅谈python jieba分词模块的基本用法
Nov 09 Python
python enumerate函数的使用方法总结
Nov 15 Python
Python使用sklearn库实现的各种分类算法简单应用小结
Jul 04 Python
Python完全识别验证码自动登录实例详解
Nov 24 Python
Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释
Jan 25 Python
文件上传服务器-jupyter 中python解压及压缩方式
Apr 22 Python
Numpy中np.random.rand()和np.random.randn() 用法和区别详解
Oct 23 Python
python 定义函数 返回值只取其中一个的实现
May 21 Python
python循环定时中断执行某一段程序的实例
Jun 29 #Python
python顺序执行多个py文件的方法
Jun 29 #Python
如何使用python把ppt转换成pdf
Jun 29 #Python
对Python的交互模式和直接运行.py文件的区别详解
Jun 29 #Python
使用python搭建服务器并实现Android端与之通信的方法
Jun 28 #Python
python全栈要学什么 python全栈学习路线
Jun 28 #Python
使用python 写一个静态服务(实战)
Jun 28 #Python
You might like
用php和MySql来与ODBC数据连接
2006/10/09 PHP
Optimizer与Debugger兼容性问题的解决方法
2008/12/01 PHP
php+websocket 实现的聊天室功能详解
2020/05/27 PHP
激活 ActiveX 控件
2006/10/09 Javascript
js 表单验证方法(实用)
2009/04/28 Javascript
jquery BS,dialog控件自适应大小
2009/07/06 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2013/10/24 Javascript
javascript中全局对象的parseInt()方法使用介绍
2013/12/19 Javascript
JavaScript框架(iframe)操作总结
2014/04/16 Javascript
javascript setinterval 的正确语法如何书写
2014/06/17 Javascript
Javascript解析URL方法详解
2014/12/05 Javascript
jQuery选择器源码解读(七):elementMatcher函数
2015/03/31 Javascript
jQuery获取及设置表单input各种类型值的方法小结
2016/05/24 Javascript
封装的dialog插件 基于bootstrap模态对话框的简单扩展
2016/08/10 Javascript
JavaScript类的写法
2016/09/17 Javascript
JS 调用微信扫一扫功能
2016/12/22 Javascript
vue.js的安装方法
2017/05/12 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
浅谈Node.js 子进程与应用场景
2018/01/24 Javascript
vant(ZanUi)结合async-validator实现表单验证的方法
2018/12/06 Javascript
关于Layui Table隐藏列问题
2019/09/16 Javascript
js制作提示框插件
2020/12/24 Javascript
[48:21]Mski vs VGJ.S Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
Python使用正则表达式过滤或替换HTML标签的方法详解
2017/09/25 Python
Python通过调用mysql存储过程实现更新数据功能示例
2018/04/03 Python
python随机在一张图像上截取任意大小图片的方法
2019/01/24 Python
python time.sleep()是睡眠线程还是进程
2019/07/09 Python
简单了解python shutil模块原理及使用方法
2020/04/28 Python
PyTorch-GPU加速实例
2020/06/23 Python
python中_del_还原数据的方法
2020/12/09 Python
Daniel Wellington官方海外旗舰店:丹尼尔惠灵顿DW手表
2018/02/22 全球购物
FC-Moto英国:欧洲最大的摩托车服装和头盔商店之一
2019/08/25 全球购物
公司委托书范本
2014/04/04 职场文书
2015年计算机教师工作总结
2015/07/22 职场文书
《游戏公平》教学反思
2016/02/20 职场文书
2016年优秀少先队辅导员事迹材料
2016/02/26 职场文书