13.13 实现一个计时器

问题

你想记录程序执行多个任务所花费的时间

解决方案

time 模块包含很多函数来执行跟时间有关的函数。尽管如此,通常我们会在此基础之上构造一个更高级的接口来模拟一个计时器。例如:

  1. import time
  2.  
  3. class Timer:
  4. def __init__(self, func=time.perf_counter):
  5. self.elapsed = 0.0
  6. self._func = func
  7. self._start = None
  8.  
  9. def start(self):
  10. if self._start is not None:
  11. raise RuntimeError('Already started')
  12. self._start = self._func()
  13.  
  14. def stop(self):
  15. if self._start is None:
  16. raise RuntimeError('Not started')
  17. end = self._func()
  18. self.elapsed += end - self._start
  19. self._start = None
  20.  
  21. def reset(self):
  22. self.elapsed = 0.0
  23.  
  24. @property
  25. def running(self):
  26. return self._start is not None
  27.  
  28. def __enter__(self):
  29. self.start()
  30. return self
  31.  
  32. def __exit__(self, *args):
  33. self.stop()

这个类定义了一个可以被用户根据需要启动、停止和重置的计时器。它会在 elapsed 属性中记录整个消耗时间。下面是一个例子来演示怎样使用它:

  1. def countdown(n):
  2. while n > 0:
  3. n -= 1
  4.  
  5. # Use 1: Explicit start/stop
  6. t = Timer()
  7. t.start()
  8. countdown(1000000)
  9. t.stop()
  10. print(t.elapsed)
  11.  
  12. # Use 2: As a context manager
  13. with t:
  14. countdown(1000000)
  15.  
  16. print(t.elapsed)
  17.  
  18. with Timer() as t2:
  19. countdown(1000000)
  20. print(t2.elapsed)

讨论

本节提供了一个简单而实用的类来实现时间记录以及耗时计算。同时也是对使用with语句以及上下文管理器协议的一个很好的演示。

在计时中要考虑一个底层的时间函数问题。一般来说,使用 time.time()time.clock() 计算的时间精度因操作系统的不同会有所不同。而使用 time.perf_counter() 函数可以确保使用系统上面最精确的计时器。

上述代码中由 Timer 类记录的时间是钟表时间,并包含了所有休眠时间。如果你只想计算该进程所花费的CPU时间,应该使用 time.process_time() 来代替:

  1. t = Timer(time.process_time)
  2. with t:
  3. countdown(1000000)
  4. print(t.elapsed)

time.perf_counter()time.process_time() 都会返回小数形式的秒数时间。实际的时间值没有任何意义,为了得到有意义的结果,你得执行两次函数然后计算它们的差值。

更多关于计时和性能分析的例子请参考14.13小节。

原文:

http://python3-cookbook.readthedocs.io/zh_CN/latest/c13/p13_making_stopwatch_timer.html