如何解决有没有办法对执行多次的代码块计时?
do_something_big():
do_1()
do_2()
do_3()
很容易获得运行 do_something_big()
或 do_1()
的单个实例所需的时间。但假设我有:
for _ in range(100000):
do_something_big()
是否有一种简单的方法可以计算 100,000 个 do_1
花费了多长时间?这并不难 - 您只需为每个人计时并更新一些全局状态以跟踪总时间。但是是否已经构建了一个实用程序来为我抽象它?
解决方法
我建议使用例如c配置文件。这个包会为你的代码中的每个函数计时,并以一种很好的格式输出:
import cProfile
pr = cProfile.Profile()
pr.enable()
run_your_program_here()
pr.disable()
pr.print_stats(sort='tottime')
最后一行中的 sort 参数将根据您给定的选项对输出进行排序。您可以阅读更多相关信息here:
ncalls – 函数/方法被调用的次数(如果递归调用相同的函数/方法,则 ncalls 有两个值,例如 120/20,其中第一个是真实调用次数,第二个是直接调用次数)
tottime – 不包括其他函数/方法时间的总时间(以秒为单位)
percall – 执行函数的平均时间(每次调用)
cumtime——以秒为单位的总时间包括它调用的其他函数的时间
percall – 与之前的 percall 类似,但是这个包括网络延迟线程睡眠等......
在您的情况下,我会使用 'tottime' 并查看 do_1 花费了多少时间。
,这是一个装饰器作为您正在寻找的实用程序。灵感来自here和here。
我们创建了一个装饰器 @timeit
。我们使用这个装饰器来注释我们的方法,它带有一个可选的 n
参数。当达到 n
次调用时,打印此方法的时间指标,否则在每次调用时打印。
from functools import wraps
from time import time
from collections import defaultdict
timedata = defaultdict(lambda : (0,0.0))
def timeit(*decArgs,**decKw):
def _timeit(func):
@wraps(func)
def timed(*args,**kw):
name = func.__name__.upper()
n = decKw.get('n',1)
if timedata[name][0] >= n:
return func(*args,**kw)
ts = time()
result = func(*args,**kw)
te = time()
duration = int((te - ts) * 1000)
cnt,ave = timedata[name]
cnt += 1
timedata[name] = (cnt,((cnt-1) * ave + duration) / cnt)
if n == cnt:
print(f'{name:30s}: [{n:6d}x] -> {ave*cnt:7.3f}ms ({ave:6.3f}ms ave)')
timedata[name] = (0,0.0)
return result
return timed
return _timeit
用法:
from random import random
@timeit(n=100)
def do_1():
sleep(random()/1000)
@timeit(n=3)
def do_something_big():
for _ in range(200):
do_1()
for _ in range(5):
do_something_big()
输出:
DO_1 : [ 100x] -> 19.192ms ( 0.192ms ave)
DO_1 : [ 100x] -> 23.232ms ( 0.232ms ave)
DO_1 : [ 100x] -> 24.242ms ( 0.242ms ave)
DO_1 : [ 100x] -> 18.182ms ( 0.182ms ave)
DO_1 : [ 100x] -> 14.141ms ( 0.141ms ave)
DO_1 : [ 100x] -> 23.232ms ( 0.232ms ave)
DO_SOMETHING_BIG : [ 3x] -> 393.000ms (131.000ms ave)
DO_1 : [ 100x] -> 27.273ms ( 0.273ms ave)
DO_1 : [ 100x] -> 22.222ms ( 0.222ms ave)
DO_1 : [ 100x] -> 21.212ms ( 0.212ms ave)
DO_1 : [ 100x] -> 24.242ms ( 0.242ms ave)
,
以下是我在 Internet https://realpython.com/python-timer/ 上找到的内容: 您将为 Python 计时器添加可选名称。您可以将该名称用于两个不同的目的:
稍后在您的代码中查找经过的时间 累积同名定时器 要将名称添加到您的 Python 计时器,您需要对 timer.py 进行另外两项更改。首先,Timer 应该接受名称作为参数。其次,当计时器停止时,应将经过的时间添加到 .timers 中:
类定时器: 计时器 = dict()
def __init__(
self,name=None,text="Elapsed time: {:0.4f} seconds",logger=print,):
self._start_time = None
self.name = name
self.text = text
self.logger = logger
# Add new named timers to dictionary of timers
if name:
self.timers.setdefault(name,0)
# Other methods are unchanged
def stop(self):
"""Stop the timer,and report the elapsed time"""
if self._start_time is None:
raise TimerError(f"Timer is not running. Use .start() to start it")
elapsed_time = time.perf_counter() - self._start_time
self._start_time = None
if self.logger:
self.logger(self.text.format(elapsed_time))
if self.name:
self.timers[self.name] += elapsed_time
return elapsed_time
请注意,将新的 Python 计时器添加到 .timers 时,您使用了 .setdefault()。这是一个很棒的功能,它仅在字典中尚未定义名称时才设置值。如果名称已在 .timers 中使用,则该值保持不变。这允许您累积多个计时器:
>>> from timer import Timer
>>> t = Timer("accumulate")
>>> t.start()
>>> t.stop() # A few seconds later
Elapsed time: 3.7036 seconds
3.703554293999332
>>> t.start()
>>> t.stop() # A few seconds later
Elapsed time: 2.3449 seconds
2.3448921170001995
>>> Timer.timers
{'accumulate': 6.0484464109995315}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。