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系列之新版本导入httplib模块报ImportError解决方案
May 23 Python
用Python编写脚本使IE实现代理上网的教程
Apr 23 Python
python学习之第三方包安装方法(两种方法)
Jul 30 Python
编写Python小程序来统计测试脚本的关键字
Mar 12 Python
Python中的并发处理之asyncio包使用的详解
Apr 03 Python
Python基于win32ui模块创建弹出式菜单示例
May 09 Python
Python实现的json文件读取及中文乱码显示问题解决方法
Aug 06 Python
Python multiprocess pool模块报错pickling error问题解决方法分析
Mar 20 Python
树莓派实现移动拍照
Jun 22 Python
详解Pandas之容易让人混淆的行选择和列选择
Jul 10 Python
python Pandas库基础分析之时间序列的处理详解
Jul 13 Python
tensorflow 实现自定义layer并添加到计算图中
Feb 04 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
基于header的一些常用指令详解
2013/06/06 PHP
linux环境apache多端口配置虚拟主机的方法深入介绍
2013/06/09 PHP
Drupal读取Excel并导入数据库实例
2014/03/02 PHP
php将图片文件转换成二进制输出的方法
2015/06/10 PHP
IE浏览器打印的页眉页脚设置解决方法
2009/12/08 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
JavaScript中为元素加上name属性的方法
2011/05/09 Javascript
js操作table示例(个人心得)
2013/11/29 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
JS+CSS实现大气清新的滑动菜单效果代码
2015/10/22 Javascript
jquery实现的V字形显示效果代码
2015/10/27 Javascript
Node.js中npm常用命令大全
2016/06/09 Javascript
EasyUI学习之Combobox下拉列表(1)
2016/12/29 Javascript
微信小程序 弹窗自定义实例代码
2017/03/08 Javascript
windows下vue.js开发环境搭建教程
2017/03/20 Javascript
jQuery 实现鼠标画框并对框内数据选中的实例代码
2017/08/29 jQuery
微信小程序日历效果
2018/12/29 Javascript
Nuxt项目支持eslint+pritter+typescript的实现
2019/05/20 Javascript
express + jwt + postMan验证实现持久化登录
2019/06/05 Javascript
Vue 动态添加路由及生成菜单的方法示例
2019/06/20 Javascript
使用Node.js实现base64和png文件相互转换的方法
2020/03/11 Javascript
[58:37]Serenity vs Fnatic 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
通过自学python能找到工作吗
2020/06/21 Python
Python Django路径配置实现过程解析
2020/11/05 Python
jupyter notebook快速入门及使用详解
2020/11/13 Python
您的健身减肥和健康饮食专家:vitafy
2017/06/06 全球购物
Brasty罗马尼亚:购买手表、香水、化妆品、珠宝
2020/04/21 全球购物
毕业生优秀推荐信
2013/11/26 职场文书
服务行业个人求职的自我评价
2013/12/12 职场文书
经验丰富大学生村干部自我鉴定
2014/01/22 职场文书
理工大学毕业生自荐信范文
2014/02/22 职场文书
社区学习雷锋活动总结
2014/04/25 职场文书
应聘会计求职信
2014/06/11 职场文书
党员教师群众路线个人整改措施
2014/10/28 职场文书
婚庆答谢词
2015/01/04 职场文书
婚礼伴郎致辞
2015/07/28 职场文书