在Python中计时程序运行时间的几种方法
在实际工作中,我们常常需要知道程序的实际运行时间(wall-clock time, real time)。本文就介绍了几种在Python中计时程序运行耗时的方法。
1. 一般方法
最为常见的方法,就是在代码的开头和结尾分别获取时间戳,然后两者之差便是程序运行时间。
import time
def do_something(nsec=0):
if isinstance(nsec, (int, float)):
time.sleep(nsec) # 模拟程序运行耗时
if __name__ == "__main__":
start_time = time.perf_counter() # 记录开始时间戳
do_something(3)
do_something(1)
do_something(0.5)
end_time = time.perf_counter() # 记录结束时间戳
print(f"耗时 {end_time - start_time:.3f} s")
这是最简单直接的方法,但问题是当需要计时的部分很多的时候,会导致大量的重复代码。
2. 基于上下文管理器
相比之下,使用Python的上下文管理器(context manager)是更加优雅,复用性更好的解决方案。Python的上下文管理器机制是用来更加方便地管理如文件、数据库连接、锁等资源的,确保在使用结束后恰当地关闭及释放资源,以避免造成泄露。
然而,上下文管理器的用途不仅限于资源的管理,其适合于所有的代码开始和结束的成对操作,就比如计时程序的运行时间。
import time
class Timer:
"""
按照 xxh xxm xxs格式计时程序运行时间的计时上下文管理器
"""
def __init__(self, code_part):
self._part = code_part
def __enter__(self):
self._enter_time = time.perf_counter()
def __exit__(self, *exc_args): # 不做异常处理,因此将异常相关的参数打包
time_span = time.perf_counter() - self._enter_time
hours, seconds = divmod(time_span, 3600)
minutes, seconds = divmod(seconds, 60)
print(f"{self._part}耗时 {int(hours)}h {int(minutes)}m {seconds:.2f}s")
def do_something(nsec=0):
if isinstance(nsec, (int, float)):
time.sleep(nsec) # 模拟程序运行耗时
if __name__ == "__main__":
with Timer("Main"):
with Timer("Part1"):
do_something(0.3)
with Timer("Part2"), open("demo_file.txt", "wt") as f:
f.write("Hello, World\n")
do_something(2)
do_something(1)
3. 基于装饰器
使用Python的装饰器特性,可以十分方便地在函数水平添加计时器,计时单个函数的运行时间。
import time
from functools import wraps
def timer(func):
@wraps(func)
def inner(*args, **kwargs):
start_time = time.perf_counter()
retval = func(*args, **kwargs)
time_span = time.perf_counter() - start_time
hours, seconds = divmod(time_span, 3600)
minutes, seconds = divmod(seconds, 60)
print(f"{func.__name__}耗时 {int(hours)}h {int(minutes)}m {seconds:.2f}s")
return retval
return inner
@timer
def do_something(nsec=0):
if isinstance(nsec, (int, float)):
time.sleep(nsec) # 模拟程序运行耗时
@timer
def main():
do_something(1)
time.sleep(0.5)
if __name__ == "__main__":
main()
作者:NameError_sfj