Python功能点实现:函数级/代码块级计时器


Posted in Python onJanuary 02, 2019

工程中我们常常需要对某一个函数或者一块代码计时,从而监测系统关键位置的性能。计时方法是在代码块前后分别记录当前系统时间,然后两者相减得到代码块的耗时。最简单原始的实现类似:

from datetime import datetime
start = datetime.now()
# some code you want to measure
end = datetime.now()
print("Processing time for {} is: {} seconds".format('You Name It', elapse))

这种方式缺点明显:假如系统内有很多地方都需要计时,那么每个地方都需要插入这样的计时代码,首先是重复性工作很麻烦,其次这样会降低代码的可读性,干扰对业务逻辑的理解。本文将给出一些更好的实现,主要涉及的技术是装饰器(Decorator)和运行时上下文(runtime context)。

基于装饰器的函数级计时器

第一种计时器是比较常见的函数级计时器,通过装饰器完成,将原函数改装成拥有计时功能的新函数,使其可以完成运行原来函数和计时两件事。在使用时,只用在需要计时功能的函数代码前加上类似@timer的语法糖,这样每次调用原函数时,运行的将会是新函数。这样就大大减少了重复性劳动。

具体实现如下:

from datetime import datetime
def timer(func):
  '''Function Level Timer via Decorator'''
  def timed(*args, **kwargs):
    start = datetime.now()
    result = func(*args, **kwargs)
    end = datetime.now()
    elapse = (end - start).total_seconds()
    print("Processing time for {} is: {} seconds".format(func.__name__, elapse))
    return result
  return timed
@timer
def test_1(a):
  '''Function Level'''
  a *= 2
  return a
if __name__ == '__main__':
  print(test_1(1))

基于上下文的代码块级计时器

装饰器实现的计时器可以为函数添加计时功能,可以满足大部分情况的需要,但是假如我们想要更灵活一些,对任意一段连续的代码块做计时,怎样做?使用原始的插计时代码的方法显然不是我们想要的;也可以将代码块重构成一个函数,再在上面加装饰器,然而这就显得不够优雅。因此我做出了下面的实现。

首先了解上下文管理的概念。大致是说Python中允许创建一种叫上下文管理器(Context Manager)的对象,它可以管理一个代码块执行时的上下文信息。具体的方法是创建一个类,并为其实现object.__enter__和object.__exit__方法,前者在进入代码块时自动执行,后者在完成代码块执行时自动执行。

在使用时,通过with和as关键字,将__enter__的返回值绑定到某一个变量名,这个返回值里可以储存代码块运行过程中得到的一些信息,在这里就是运行时间啦。具体的实现是创建一个计时器类Timer,在enter时记录代码块运行的开始时间,exit时记录完成时间、计算并储存耗时到Timer实例中。在使用时,将with Timer() as t加到要计时的代码块前面,t.elapse中将会储存代码块耗时,可以任意使用。

在这个基础上,我们还可以做出一个装饰器timer_来实现基于上下文的函数级计时器。

具体实现如下:

class Timer(object):
  '''Code Block Level Timer via Context'''
  def __enter__(self):
    self.start = datetime.now()
    return self
  def __exit__(self, *args):
    self.end = datetime.now()
    self.elapse = (self.end - self.start).total_seconds()
def timer_(func):
  '''Function Level Timer via Context & with Statement'''
  def timed(*args, **kw):
    with Timer() as t:
      result = func(*args, **kw)
    print("Processing time for {} is: {} seconds".format(func.__name__, t.elapse))
    return result
  return timed
def test_2(a):
  '''Code Block Level'''
  with Timer() as t:
    a *= 2
  print("Processing time for {} is: {} seconds".format('You Name It', t.elapse))
  return a
@timer_
def test_3(a):
  '''Function Level'''
  a *= 2
  return a
if __name__ == '__main__':
  print(test_2(2))
  print(test_3(3))

更灵活的实现

更优雅地,我们还可以使用contextlib自带的ContextDecorator,参考官方示例,做出既可以with又可以作为装饰器的计时器timer_elegant:

from datetime import datetime
from contextlib import ContextDecorator
class timer_elegant(ContextDecorator):
  '''Elegant Timer via ContextDecorator'''
  def __init__(self, name):
    self.name = name
  def __enter__(self):
    self.start = datetime.now()
  def __exit__(self, *args):
    self.end = datetime.now()
    self.elapse = (self.end - self.start).total_seconds()
    print("Processing time for {} is: {} seconds".format(self.name, self.elapse))
@timer_elegant('test_4')
def test_4(a):
  a *= 2
  return a
def test_5(a):
  a *= 2
  return a
if __name__ == '__main__':
  print(test_4(4))
 
  with timer_elegant('test 5'):
    result_5 = test_5(5)
  print(result_5)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Python 相关文章推荐
python实现多线程的两种方式
May 22 Python
django1.8使用表单上传文件的实现方法
Nov 04 Python
Python 实现某个功能每隔一段时间被执行一次的功能方法
Oct 14 Python
Python 函数list&read&seek详解
Aug 28 Python
Python接口测试get请求过程详解
Feb 28 Python
python3通过qq邮箱发送邮件以及附件
May 20 Python
使用OpenCV对车道进行实时检测的实现示例代码
Jun 19 Python
keras的backend 设置 tensorflow,theano操作
Jun 30 Python
python3列表删除大量重复元素remove()方法的问题详解
Jan 04 Python
python实现黄金分割法的示例代码
Apr 28 Python
详解Python生成器和基于生成器的协程
Jun 03 Python
Python实现Excel文件的合并(以新冠疫情数据为例)
Mar 20 Python
详解如何在Apache中运行Python WSGI应用
Jan 02 #Python
漂亮的Django Markdown富文本app插件的实现
Jan 02 #Python
对Python发送带header的http请求方法详解
Jan 02 #Python
Django渲染Markdown文章目录的方法示例
Jan 02 #Python
使用python 打开文件并做匹配处理的实例
Jan 02 #Python
对Xpath 获取子标签下所有文本的方法详解
Jan 02 #Python
python之验证码生成(gvcode与captcha)
Jan 02 #Python
You might like
解析htaccess伪静态的规则
2013/06/18 PHP
PHP函数http_build_query使用详解
2014/08/20 PHP
php禁止直接从浏览器输入地址访问.php文件的方法
2014/11/04 PHP
ecshop 2.72如何修改后台访问地址
2015/03/03 PHP
CentOS系统中PHP安装扩展的方式汇总
2017/04/09 PHP
基于jquery实现的类似百度搜索的输入框自动完成功能
2011/08/23 Javascript
JavaScript修改css样式style动态改变元素样式
2013/12/16 Javascript
自己用jQuery写了一个图片的马赛克消失效果
2014/05/04 Javascript
jquery获取radio值(单选组radio)
2014/10/16 Javascript
jQuery中$this和$(this)的区别介绍(一看就懂)
2015/07/06 Javascript
简介EasyUI datagrid editor combogrid搜索框的实现
2016/04/01 Javascript
JS和jQuery使用submit方法无法提交表单的原因分析及解决办法
2016/05/17 Javascript
jquery设置表单元素为不可用的简单代码
2016/07/04 Javascript
js计算系统当前日期是星期几的方法
2016/07/14 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
2016/11/28 Javascript
js 动态生成json对象、时时更新json对象的方法
2016/12/02 Javascript
Bootstrap面板使用方法
2017/01/16 Javascript
vue动态删除从数据库倒入列表的某一条方法
2018/09/29 Javascript
Vue 组件封装 并使用 NPM 发布的教程
2018/09/30 Javascript
jquery实现购物车基本功能
2019/10/25 jQuery
详解vue修改elementUI的分页组件视图没更新问题
2020/11/13 Javascript
python爬虫 正则表达式使用技巧及爬取个人博客的实例讲解
2017/10/20 Python
Python与R语言的简要对比
2017/11/14 Python
python3实现多线程聊天室
2018/12/12 Python
Python3环境安装Scrapy爬虫框架过程及常见错误
2019/07/12 Python
Django Path转换器自定义及正则代码实例
2020/05/29 Python
python redis存入字典序列化存储教程
2020/07/16 Python
python中的对数log函数表示及用法
2020/12/09 Python
德国净水壶和滤芯品牌:波尔德PearlCo(家用净水器)
2020/04/29 全球购物
shell程序中如何注释
2012/01/28 面试题
Overload和Override的区别
2012/09/02 面试题
音乐教学随笔感言
2014/02/19 职场文书
祖国在我心中演讲稿300字
2014/05/04 职场文书
移交协议书
2014/08/19 职场文书
教师党的群众路线教育实践活动学习笔记
2014/11/05 职场文书
PyTorch中permute的使用方法
2022/04/26 Python