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

  

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

        从datetime进口datetime   开始=datetime.now ()   #你想测量一些代码   结束=datetime.now ()   打印(“处理时间{}:{}秒”。格式(“应有尽有”,推移))      

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

  

<>强基于装饰器的函数级计时器

  

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

  

具体实现如下:

        从datetime进口datetime   def计时器(函数):   “功能水平计时器通过装饰”   def定时(* args, * * kwargs):   开始=datetime.now ()   结果=func (* args, * * kwargs)   结束=datetime.now ()   推移=(结束-开始).total_seconds ()   打印(“处理时间{}:{}秒”.format(函数。__name__,推移))   返回结果   返回时间   @timer   def test_1(一个):   “功能”水平   *=2   返回一个   if __name__==癬_main__”:   打印(test_1 (1)      

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

  

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

  

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

  

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

  

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

  

具体实现如下:

        类计时器(对象):   “代码块水平计时器通过上下文”   def __enter__(自我):   自我。开始=datetime.now ()   回归自我   def __exit__(自我,* args):   自我。结束=datetime.now ()   自我。推移=(自我。结束- self.start) .total_seconds ()   def timer_(函数):   “通过上下文和计时器功能水平;声明”的   def定时(* args, * *千瓦):   用定时器和t ():   结果=func (* args, * *千瓦)   打印(“处理时间{}:{}秒”.format(函数。__name__, t.elapse))   返回结果   返回时间   def test_2(一个):   “代码块的水平”   用定时器和t ():   *=2   打印(“处理时间{}:{}秒”。格式(“应有尽有”,t.elapse))   返回一个   @timer_   def test_3(一个):   “功能”水平   *=2   返回一个   if __name__==癬_main__”:   打印(test_2 (2))   打印(test_3 (3)      

<强>更灵活的实现

  

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

        从datetime进口datetime   从contextlib进口ContextDecorator   类timer_elegant (ContextDecorator):   “优雅的计时器通过ContextDecorator”   def __init__(自我、名称):   self.name=名字   def __enter__(自我):   自我。开始=datetime.now ()   def __exit__(自我,* args):   自我。结束=datetime.now ()   自我。推移=(自我。结束- self.start) .total_seconds ()   打印(“处理时间{}:{}秒”.format (self.name self.elapse))   @timer_elegant (“test_4”)   def test_4(一个):   *=2   返回一个   def test_5(一个):   *=2   返回一个   if __name__==癬_main__”:   打印(test_4 (4))      与timer_elegant(测试5):   result_5=test_5 (5)   打印(result_5)

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