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超简单解决约瑟夫环问题
May 12 Python
Python求两个文本文件以行为单位的交集、并集与差集的方法
Jun 17 Python
Python中的os.path路径模块中的操作方法总结
Jul 07 Python
python实现稀疏矩阵示例代码
Jun 09 Python
Python爬虫基础之XPath语法与lxml库的用法详解
Sep 13 Python
python 输出所有大小写字母的方法
Jan 02 Python
基于python if 判断选择结构的实例详解
May 06 Python
CentOS6.9 Python环境配置(python2.7、pip、virtualenv)
May 06 Python
python tkinter组件摆放方式详解
Sep 16 Python
Django 路由层URLconf的实现
Dec 30 Python
python 写一个文件分发小程序
Dec 05 Python
基于Python实现流星雨效果的绘制
Mar 18 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
4.与数据库的连接
2006/10/09 PHP
php 使用post,get的一种简洁方式
2010/04/25 PHP
优化PHP代码技巧的小结
2013/06/02 PHP
关于PHP文件的自动运行方法分析
2016/05/13 PHP
PHP类的特性实例分析
2016/09/28 PHP
分享5个非常有用的Laravel Blade指令
2018/05/30 PHP
laravel5.6 框架邮件队列database驱动简单demo示例
2020/01/26 PHP
浅析PHP反序列化中过滤函数使用不当导致的对象注入问题
2020/02/15 PHP
javascript函数库-集合框架
2007/04/27 Javascript
JS保留两位小数,多位小数的示例代码
2014/01/07 Javascript
基于 Docker 开发 NodeJS 应用
2014/07/30 NodeJs
javascript中hasOwnProperty() 方法使用指南
2015/03/09 Javascript
JS实现页面进入和返回定位到具体位置
2016/12/08 Javascript
JavaScript运动框架 多物体任意值运动(三)
2017/05/17 Javascript
AngularJS表单验证功能分析
2017/05/26 Javascript
Vue ElementUI之Form表单验证遇到的问题
2017/08/21 Javascript
Node.js使用Koa搭建 基础项目
2018/01/08 Javascript
Python中字典(dict)合并的四种方法总结
2017/08/10 Python
Python实现二维数组按照某行或列排序的方法【numpy lexsort】
2017/09/22 Python
Python3使用SMTP发送带附件邮件
2020/06/16 Python
Python变量类型知识点总结
2019/02/18 Python
python算法与数据结构之单链表的实现代码
2019/06/27 Python
通过 Django Pagination 实现简单分页功能
2019/11/11 Python
python GUI库图形界面开发之PyQt5中QMainWindow, QWidget以及QDialog的区别和选择
2020/02/26 Python
Python %r和%s区别代码实例解析
2020/04/03 Python
Python的logging模块基本用法
2020/12/24 Python
使用css3背景渐变中的透明度来设置不同颜色的背景渐变
2014/03/31 HTML / CSS
Html5如何唤起百度地图App的方法
2019/01/27 HTML / CSS
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
安全员岗位职责
2013/11/11 职场文书
大学专科求职信
2014/07/02 职场文书
详解CSS玩转图片Base64编码
2021/05/25 HTML / CSS
Mysql排查分析慢sql之explain实战案例
2022/04/19 MySQL
Python绘制散乱的点构成的图的方法
2022/04/21 Python
Windows Server 2008 修改远程登录端口以及配置防火墙
2022/04/28 Servers
详解Anyscript开发指南绕过typescript类型检查
2022/09/23 Javascript