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基础教程之python消息摘要算法使用示例
Feb 10 Python
Python 实现 贪吃蛇大作战 代码分享
Sep 07 Python
Python序列操作之进阶篇
Dec 08 Python
简单实现Python爬取网络图片
Apr 01 Python
详解python单元测试框架unittest
Jul 02 Python
python实现括号匹配的思路详解
Aug 23 Python
用python代码将tiff图片存储到jpg的方法
Dec 04 Python
python Pexpect 实现输密码 scp 拷贝的方法
Jan 03 Python
12个Python程序员面试必备问题与答案(小结)
Jun 24 Python
将python2.7添加进64位系统的注册表方式
Nov 20 Python
python计算Content-MD5并获取文件的Content-MD5值方式
Apr 03 Python
Matplotlib绘制混淆矩阵的实现
May 27 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
通过文字传递创建的图形按钮
2006/10/09 PHP
PHP header()函数常用方法总结
2014/04/11 PHP
支付宝接口开发集成支付环境小结
2015/03/17 PHP
Laravel中批量赋值Mass-Assignment的真正含义详解
2017/09/29 PHP
JavaScript 动态创建VML的方法
2009/10/14 Javascript
Prototype源码浅析 String部分(四)之补充
2012/01/16 Javascript
javascript 事件处理、鼠标拖动效果实现方法详解
2012/05/11 Javascript
javascript放大镜效果的简单实现
2013/12/09 Javascript
深入理解JavaScript系列(41):设计模式之模板方法详解
2015/03/04 Javascript
jQuery实现文件上传进度条特效
2015/08/12 Javascript
JavaScript中removeChild 方法开发示例代码
2016/08/15 Javascript
微信小程序 Audio API详解及实例代码
2016/09/30 Javascript
jQuery实现淡入淡出的模态框
2017/02/09 Javascript
前端开发之CSS原理详解
2017/03/11 Javascript
js弹出窗口简单实现代码
2017/03/22 Javascript
基于JavaScript定位当前的地理位置
2017/04/11 Javascript
VUE element-ui 写个复用Table组件的示例代码
2017/11/18 Javascript
jQuery实现验证表单密码一致性及正则表达式验证邮箱、手机号的方法
2017/12/05 jQuery
Vue在页面右上角实现可悬浮/隐藏的系统菜单
2018/05/04 Javascript
Vue formData实现图片上传
2019/08/20 Javascript
Python简单实现socket信息发送与监听功能示例
2018/01/03 Python
python利用smtplib实现QQ邮箱发送邮件
2020/05/20 Python
Python中__slots__属性介绍与基本使用方法
2018/09/05 Python
Python中xml和json格式相互转换操作示例
2018/12/05 Python
解决新版Pycharm中Matplotlib图像不在弹出独立的显示窗口问题
2019/01/15 Python
20行python代码的入门级小游戏的详解
2019/05/05 Python
python3用PIL把图片转换为RGB图片的实例
2019/07/04 Python
pytorch 使用单个GPU与多个GPU进行训练与测试的方法
2019/08/19 Python
Django中间件拦截未登录url实例详解
2019/09/03 Python
iphoneX 适配客户端H5页面的方法教程
2017/12/08 HTML / CSS
感恩节活动方案
2014/01/27 职场文书
公务员试用期满考核材料
2014/05/22 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
销售员未完成销售业绩的检讨书
2014/10/12 职场文书
2015年元旦主持词结束语
2014/12/14 职场文书
Java获取e.printStackTrace()打印的信息方式
2021/08/07 Java/Android