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 相关文章推荐
pip 错误unused-command-line-argument-hard-error-in-future解决办法
Jun 01 Python
Python基于二分查找实现求整数平方根的方法
May 12 Python
python多个模块py文件的数据共享实例
Jan 11 Python
python 通过可变参数计算n个数的乘积方法
Jun 13 Python
pandas.cut具体使用总结
Jun 24 Python
python FTP批量下载/删除/上传实例
Dec 22 Python
python实现的批量分析xml标签中各个类别个数功能示例
Dec 30 Python
基于tensorflow指定GPU运行及GPU资源分配的几种方式小结
Feb 03 Python
解决使用python print打印函数返回值多一个None的问题
Apr 09 Python
PyCharm最新激活码(2020/10/27全网最新)
Oct 27 Python
在Windows下安装配置CPU版的PyTorch的方法
Apr 02 Python
超级详细实用的pycharm常用快捷键
May 12 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获取搜索引擎关键字来源的函数(支持百度和谷歌等搜索引擎)
2012/10/03 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
在js中使用&quot;with&quot;语句中跨frame的变量引用问题
2007/03/08 Javascript
jQuery focus和blur事件的应用详解
2014/01/26 Javascript
Jquery弹出层插件ThickBox的使用方法
2014/12/09 Javascript
超级给力的JavaScript的React框架入门教程
2015/07/02 Javascript
jQuery动画效果相关方法实例分析
2015/12/31 Javascript
Vue生命周期示例详解
2017/04/12 Javascript
JS简单实现点击跳转登陆邮箱功能的方法
2017/10/31 Javascript
详解vue+css3做交互特效的方法
2017/11/20 Javascript
webpack下实现动态引入文件方法
2018/02/22 Javascript
vue中rem的配置的方法示例
2018/08/30 Javascript
vue-router beforeEach跳转路由验证用户登录状态
2018/12/26 Javascript
webpack自动打包和热更新的实现方法
2019/06/24 Javascript
17道题让你彻底理解JS中的类型转换
2019/08/08 Javascript
vue使用高德地图根据坐标定位点的实现代码
2019/08/22 Javascript
js实现聊天对话框
2020/02/08 Javascript
python实现教务管理系统
2018/03/12 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
通过字符串导入 Python 模块的方法详解
2019/10/27 Python
python 利用turtle模块画出没有角的方格
2019/11/23 Python
python获取array中指定元素的示例
2019/11/26 Python
Python configparser模块应用过程解析
2020/08/14 Python
python实现测试工具(二)——简单的ui测试工具
2020/10/19 Python
python实现双人五子棋(终端版)
2020/12/30 Python
几个Linux面试题笔试题
2016/08/01 面试题
小学教师岗位职责
2013/11/25 职场文书
物流管理毕业生自荐信范文
2014/03/15 职场文书
2014年感恩母亲演讲稿
2014/05/27 职场文书
高一军训的心得体会
2014/09/01 职场文书
单位工作证明格式模板
2014/10/04 职场文书
先进党员事迹材料
2014/12/24 职场文书
求职简历自荐信怎么写
2015/03/26 职场文书
《用字母表示数》教学反思
2016/02/17 职场文书
2019感恩宣传标语!
2019/07/05 职场文书
Python实现位图分割的效果
2021/11/20 Python