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学习笔记之os模块使用总结
Nov 03 Python
python中while循环语句用法简单实例
May 07 Python
Python素数检测实例分析
Jun 15 Python
Django中URL视图函数的一些高级概念介绍
Jul 20 Python
django用户注册、登录、注销和用户扩展的示例
Mar 19 Python
Python3随机漫步生成数据并绘制
Aug 27 Python
对Python subprocess.Popen子进程管道阻塞详解
Oct 29 Python
python钉钉机器人运维脚本监控实例
Feb 20 Python
基于Python的微信机器人开发 微信登录和获取好友列表实现解析
Aug 21 Python
PyTorch中的Variable变量详解
Jan 07 Python
Python Selenium安装及环境配置的实现
Mar 17 Python
pyspark 随机森林的实现
Apr 24 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初学者写及时补给skype用户充话费的小程序
2008/11/02 PHP
PHP对MongoDB[NoSQL]数据库的操作
2013/03/01 PHP
注释PHP和html混合代码的小技巧(分享)
2016/11/03 PHP
利用ajax和PHP实现简单的流程管理
2017/03/23 PHP
详解thinkphp5+swoole实现异步邮件群发(SMTP方式)
2017/10/13 PHP
使用js判断TextBox控件值改变然后出发事件
2014/03/07 Javascript
jQuery中triggerHandler()方法用法实例
2015/01/19 Javascript
再谈javascript常见错误及解决方法
2016/09/16 Javascript
jQuery实现立体式数字动态增加(animate方法)
2016/12/21 Javascript
如何利用JQuery实现从底部回到顶部的功能
2016/12/27 Javascript
vue.js简单配置axios的方法详解
2017/12/13 Javascript
对vue.js中this.$emit的深入理解
2018/02/23 Javascript
element-ui中的select下拉列表设置默认值方法
2018/08/24 Javascript
基于vue-cli、elementUI的Vue超简单入门小例子(推荐)
2019/04/17 Javascript
深入了解JavaScript 私有化
2019/05/30 Javascript
vue spa应用中的路由缓存问题与解决方案
2019/05/31 Javascript
基于layui内置模块(element常用元素的操作)
2019/09/20 Javascript
[47:20]DAC2018 4.4 淘汰赛 Optic vs Mineski 第一场
2018/04/05 DOTA
python写xml文件的操作实例
2014/10/05 Python
200行自定义python异步非阻塞Web框架
2017/03/15 Python
python tkinter canvas 显示图片的示例
2019/06/13 Python
python中selenium操作下拉滚动条的几种方法汇总
2019/07/14 Python
20行Python代码实现视频字符化功能
2020/04/13 Python
html5使用Canvas绘图的使用方法
2017/11/21 HTML / CSS
台湾生鲜宅配:大口市集
2017/10/14 全球购物
Saucony澳大利亚官网:美国跑鞋品牌,运动鞋中的劳斯莱斯
2018/05/05 全球购物
德国净水壶和滤芯品牌:波尔德PearlCo(家用净水器)
2020/04/29 全球购物
The North Face意大利官网:服装、背包和鞋子
2020/06/17 全球购物
简历里的自我评价
2014/01/31 职场文书
个人实习生的自我评价
2014/02/16 职场文书
体育专业求职信
2014/07/16 职场文书
教师党员学习十八届四中全会思想汇报
2014/11/03 职场文书
宝葫芦的秘密观后感
2015/06/11 职场文书
2016国庆节67周年寄语
2015/12/07 职场文书
2016年中学清明节活动总结
2016/04/01 职场文书
CSS元素定位之通过元素的标签或者元素的id、class属性定位详解
2022/09/23 HTML / CSS