测量在 Python 中经过的时间

我想要的是开始在我的代码中的某个地方开始计时,然后获取经过的时间,以衡量执行少量功能所花费的时间。我认为我使用的 timeit 模块错误,但是文档对我来说却很混乱。

import timeit

start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

答案

如果只想测量两点之间经过的挂钟时间,则可以使用time.time()

import time

start = time.time()
print("hello")
end = time.time()
print(end - start)

这给出了执行时间(以秒为单位)。

自 3.3 起,另一个选择可能是使用perf_counterprocess_time ,具体取决于您的要求。在 3.3 之前,建议使用time.clock (感谢Amber )。但是,目前不推荐使用:

在 Unix 上,以秒为单位返回当前处理器时间,以浮点数表示。精度,实际上是 “处理器时间” 含义的确切定义,取决于同名 C 函数的精度。

在 Windows 上,此函数基于 Win32 函数QueryPerformanceCounter()返回自第一次调用此函数以来经过的时间(以秒为单位)的浮点数。分辨率通常优于一微秒。

从版本 3.3 开始不推荐使用 :此功能的行为取决于平台:根据您的要求, 使用perf_counter()process_time()来具有明确定义的行为。

使用timeit.default_timer而不是timeit.timeit 。前者会自动在您的平台和 Python 版本上提供最佳时钟:

from timeit import default_timer as timer

start = timer()
# ...
end = timer()
print(end - start) # Time in seconds, e.g. 5.38091952400282

根据操作系统,将timeit.default_timer分配给 time.time()或 time.clock()。在 Python 3.3 + 上,在所有平台上, default_timertime.perf_counter() 。参见Python-time.clock()与 time.time()- 准确性?

也可以看看:

仅限 Python 3:

由于从Python 3.3 开始不推荐使用time.perf_counter() ,因此您将需要使用time.perf_counter()进行系统范围的计时,或者使用time.perf_counter() time.process_time()进行进程范围的计时,就像您以前使用time.clock()

import time

t = time.process_time()
#do some stuff
elapsed_time = time.process_time() - t

新函数process_time将不包括睡眠期间经过的时间。

有了您想计时的功能,

test.py:

def foo(): 
    # print "hello"   
    return "hello"

使用timeit的最简单方法是从命令行调用它:

% python -mtimeit -s'import test' 'test.foo()'
1000000 loops, best of 3: 0.254 usec per loop

不要试图(天真的)使用time.timetime.clock来比较功能的速度。 他们可能会产生误导性的结果

PS。不要将打印语句放在您希望计时的函数中;否则,测量的时间将取决于终端速度

使用上下文管理器执行此操作很有趣,它可以自动记住进入with块的开始时间,然后冻结块退出时的结束时间。只需一点技巧,您甚至可以通过相同的上下文管理器功能在块内获得运行时间计数。

核心库没有这个(但应该这样做)。放置到位后,您可以执行以下操作:

with elapsed_timer() as elapsed:
    # some lengthy code
    print( "midpoint at %.2f seconds" % elapsed() )  # time so far
    # other lengthy code

print( "all done at %.2f seconds" % elapsed() )

这是足以完成此任务的contextmanager代码:

from contextlib import contextmanager
from timeit import default_timer

@contextmanager
def elapsed_timer():
    start = default_timer()
    elapser = lambda: default_timer() - start
    yield lambda: elapser()
    end = default_timer()
    elapser = lambda: end-start

还有一些可运行的演示代码:

import time

with elapsed_timer() as elapsed:
    time.sleep(1)
    print(elapsed())
    time.sleep(2)
    print(elapsed())
    time.sleep(3)

请注意,通过设计此函数, elapsed()的返回值在块退出时被冻结,并且进一步的调用返回相同的持续时间(在此玩具示例中约为 6 秒)。

我喜欢这个。 timeit文档太混乱了。

from datetime import datetime 

start_time = datetime.now() 

# INSERT YOUR CODE 

time_elapsed = datetime.now() - start_time 

print('Time elapsed (hh:mm:ss.ms) {}'.format(time_elapsed))

注意,这里没有任何格式,我只是在打印输出中写了hh:mm:ss以便可以解释time_elapsed

以秒为单位的测量时间

from timeit import default_timer as timer
from datetime import timedelta

start = timer()
end = timer()
print(timedelta(seconds=end-start))

输出

0:00:01.946339

现在已经是 2020 年了,让我们以一种简洁的方式来做:

from ttictoc import TicToc
t = TicToc() ## TicToc("name")
t.tic()
# your code ...
t.toc()
print(t.elapsed)

使用此方法而不是其他方法的优点:

  1. 简洁明了。它不需要程序员编写额外的变量,例如:
    t1 = 时间()
    t2 = 时间()
    经过时间 = t2-t1
  2. 带嵌套
t = TicToc(nested=True)
t.tic()
some code1...
t.tic()
some code2...
t.tic()
some code3...
print(t.toc()) # Prints time for code 3 
print(t.toc()) # Prints time for code 2 with code 3
print(t.toc()) # Prints time for code 1 with code 2 and 3
  1. 保留井字游戏的名称。
t = TicToc("save user")
print(t.name)

请参考此链接以获取更多详细说明。

使用time.time来衡量执行情况可以为您提供命令的总体执行时间,包括计算机上其他进程所花费的运行时间。这是用户注意到的时间,但是如果您要比较不同的代码段 / 算法 / 函数 / ...,则效果不佳。

有关timeit更多信息:

如果您想对配置文件有更深入的了解:

更新 :去年我大量使用了http://pythonhosted.org/line_profiler/ ,发现它非常有用,建议使用它代替 Pythons profile 模块。

这是我在这里经过许多不错的回答以及其他几篇文章后的发现。

首先,如果要在timeittime.time之间进行辩论, timeit有两个优点:

  1. timeit选择适用于您的 OS 和 Python 版本的最佳计时器。
  2. timeit禁用垃圾收集,但是,这不是您可能想要或可能不需要的东西。

现在的问题是, timeit并不是那么简单易用,因为它需要设置,并且当您进行大量导入时,事情变得很丑陋。理想情况下,你只想要一个装饰或者使用with块和测量时间。不幸的是,对此没有内置的功能,因此您有两个选择:

选项 1:使用时间预算库

timebudget是一个通用且非常简单的库,在 pip 安装后,您只需一行代码即可使用它。

@timebudget  # Record how long this function takes
def my_method():
    # my code

选项 2:直接使用代码模块

我在下面创建了小的实用程序模块。

# utils.py
from functools import wraps
import gc
import timeit

def MeasureTime(f):
    @wraps(f)
    def _wrapper(*args, **kwargs):
        gcold = gc.isenabled()
        gc.disable()
        start_time = timeit.default_timer()
        try:
            result = f(*args, **kwargs)
        finally:
            elapsed = timeit.default_timer() - start_time
            if gcold:
                gc.enable()
            print('Function "{}": {}s'.format(f.__name__, elapsed))
        return result
    return _wrapper

class MeasureBlockTime:
    def __init__(self,name="(block)", no_print = False, disable_gc = True):
        self.name = name
        self.no_print = no_print
        self.disable_gc = disable_gc
    def __enter__(self):
        if self.disable_gc:
            self.gcold = gc.isenabled()
            gc.disable()
        self.start_time = timeit.default_timer()
    def __exit__(self,ty,val,tb):
        self.elapsed = timeit.default_timer() - self.start_time
        if self.disable_gc and self.gcold:
            gc.enable()
        if not self.no_print:
            print('Function "{}": {}s'.format(self.name, self.elapsed))
        return False #re-raise any exceptions

现在,您只需在其前面放置装饰器即可计时任何功能:

import utils

@utils.MeasureTime
def MyBigFunc():
    #do something time consuming
    for i in range(10000):
        print(i)

如果您想计时部分代码,只需将其with代码块with放入:

import utils

#somewhere in my code

with utils.MeasureBlockTime("MyBlock"):
    #do something time consuming
    for i in range(10000):
        print(i)

# rest of my code

优点:

有几个半支持的版本,所以我想指出一些重点:

  1. 出于前面所述的原因,请使用 timeit 中的 timer 代替 time.time。
  2. 在计时期间禁用 GC。
  3. 装饰器接受带有已命名或未命名参数的函数。
  4. 能够按块定时禁用打印( with utils.MeasureBlockTime() as t使用,然后为t.elapsed )。
  5. 能够为块定时保持启用 gc 的能力。