如何在 Python 中测量经过的时间?

2024-11-27 10:43:00
admin
原创
166
摘要:问题描述:我想测量执行某个函数所花费的时间。我无法开始timeit工作:import timeit start = timeit.timeit() print("hello") end = timeit.timeit() print(end - start) 解决方案 1:用于time.t...

问题描述:

我想测量执行某个函数所花费的时间。我无法开始timeit工作:

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

解决方案 1:

用于time.time()测量两点之间经过的挂钟时间:

import time

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

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


从 Python 3.3 开始,另一个选项可能是使用perf_counterprocess_time,具体取决于您的要求。在 3.3 之前,建议使用time.clock(感谢Amber )。但是,它目前已被弃用:

在 Unix 上,以浮点数形式返回当前处理器时间(以秒为单位)。精度(实际上“处理器时间”的含义)取决于同名 C 函数的精度。

在 Windows 上,此函数基于 Win32 函数,以浮点数形式返回自第一次调用此函数以来经过的挂钟秒数QueryPerformanceCounter()。精度通常优于一微秒。

自 3.3 版起已弃用:此功能的行为取决于平台:根据您的要求,使用perf_counter()process_time()代替,以获得明确定义的行为。

解决方案 2:

使用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_timer在所有平台上都是time.perf_counter() 。请参阅Python - time.clock() 与 time.time() - 准确性?

参见:

  • 优化代码

  • 如何优化速度

解决方案 3:

仅限 Python 3:

由于time.clock() 从 Python 3.3 开始已弃用,您将需要使用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将不包括睡眠期间经过的时间。

解决方案 4:

以秒为单位测量时间

from timeit import default_timer as timer
from datetime import timedelta

start = timer()

# ....
# (your code runs here)
# ...

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

输出

0:00:01.946339

解决方案 5:

给定一个你想要计时的函数,

测试.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. 不要将打印语句放在您想要计时的函数中;否则测量的时间将取决于终端的速度。

解决方案 6:

使用上下文管理器来执行此操作很有趣,它可以自动记住进入块时的开始时间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 秒)。

解决方案 7:

我更喜欢这个。doctimeit太令人困惑了。

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

解决方案 8:

以下是另一种方法:

>> from pytictoc import TicToc
>> t = TicToc() # create TicToc instance
>> t.tic() # Start timer
>> # do something
>> t.toc() # Print elapsed time
Elapsed time is 2.612231 seconds.

与传统方式相比:

>> from time import time
>> t1 = time()
>> # do something
>> t2 = time()
>> elapsed = t2 - t1
>> print('Elapsed time is %f seconds.' % elapsed)
Elapsed time is 2.612231 seconds.

安装:

pip install pytictoc

有关更多详细信息,请参阅PyPi 页面。

解决方案 9:

计算操作持续时间的最简单方法:

import time

start_time = time.monotonic()

<operations, programs>

print('seconds: ', time.monotonic() - start_time)

官方文档在这里。

解决方案 10:

这是我读过这里的许多好答案以及其他一些文章后得出的结论。

timeit首先,如果你正在和之间争论time.time,那么timeit有两个优点:

  1. timeit选择适合您的操作系统和 Python 版本的最佳计时器。

  2. timeit禁用垃圾收集,但是,这不是您可能想要或不想要的。

现在的问题是它timeit使用起来并不那么简单,因为它需要设置,而且当你有大量导入时,事情会变得很糟糕。理想情况下,你只需要一个装饰器或使用with块并测量时间。不幸的是,没有内置的可用功能,所以你有两个选择:

选项 1:使用 timebudget 库

timebudget是一个多功能且非常简单的库,在pip install 后只需一行代码即可使用它。

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

选项 2:使用我的小模块

我创建了下面这个名为timing.py的小型计时实用程序模块。只需将此文件放入您的项目中并开始使用它即可。唯一的外部依赖项是runstats,它同样很小。

现在,只需在任何函数前面放置一个装饰器就可以对其进行计时:

import timing

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

timing.print_all_timings()

如果您想要计时部分代码,则只需将其放在with块内:

import timing

#somewhere in my code

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

# rest of my code

timing.print_all_timings()

优点:

目前流传着几个不完整的版本,因此我想指出几个亮点:

  1. 由于前面描述的原因,请使用 timeit 中的计时器而不是 time.time。

  2. 如果需要,您可以在计时期间禁用 GC。

  3. 装饰器接受具有命名或未命名参数的函数。

  4. 能够以块时间禁用打印(使用with timing.MeasureBlockTime() as t然后t.elapsed)。

  5. 能够保持 gc 启用块计时。

解决方案 11:

使用time.time来测量执行时间可以让你了解命令的总体执行时间,包括计算机上其他进程所花费的运行时间。这是用户注意到的时间,但如果你想比较不同的代码片段/算法/函数/...,这并不好用。

更多信息timeit

  • 使用 timeit 模块

  • timeit——对 Python 小段代码的执行进行计时

如果您想更深入地了解分析:

更新:去年我经常使用http://pythonhosted.org/line_profiler/ ,发现它非常有用,建议使用它来代替 Pythons 配置文件模块。

解决方案 12:

在python3上:

from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)

优雅而简短。

输出:

1.001345009999568

解决方案 13:

这是另一个用于计时代码的上下文管理器 -

用法:

from benchmark import benchmark

with benchmark("Test 1+1"):
    1+1
=>
Test 1+1 : 1.41e-06 seconds

或者,如果你需要时间值

with benchmark("Test 1+1") as b:
    1+1
print(b.time)
=>
Test 1+1 : 7.05e-07 seconds
7.05233786763e-07

基准测试.py

from timeit import default_timer as timer

class benchmark(object):

    def __init__(self, msg, fmt="%0.3g"):
        self.msg = msg
        self.fmt = fmt

    def __enter__(self):
        self.start = timer()
        return self

    def __exit__(self, *args):
        t = timer() - self.start
        print(("%s : " + self.fmt + " seconds") % (self.msg, t))
        self.time = t

改编自http://dabeaz.blogspot.fr/2010/02/context-manager-for-timing-benchmarks.html

解决方案 14:

python cProfile 和 pstats 模块为测量某些函数中经过的时间提供了强大的支持,而无需在现有函数周围添加任何代码。

例如如果你有一个python脚本timeFunctions.py:

import time

def hello():
    print "Hello :)"
    time.sleep(0.1)

def thankyou():
    print "Thank you!"
    time.sleep(0.05)

for idx in range(10):
    hello()

for idx in range(100):
    thankyou()

要运行分析器并生成文件统计信息,您只需运行:

python -m cProfile -o timeStats.profile timeFunctions.py

这样做的目的是使用 cProfile 模块来分析 timeFunctions.py 中的所有函数,并收集 timeStats.profile 文件中的统计数据。请注意,我们不必向现有模块 (timeFunctions.py) 添加任何代码,并且可以使用任何模块来完成此操作。

一旦您有了统计文件,您就可以按如下方式运行 pstats 模块:

python -m pstats timeStats.profile

这将运行交互式统计浏览器,为您提供许多不错的功能。对于您的特定用例,您只需检查函数的统计数据即可。在我们的示例中,检查两个函数的统计数据会显示以下内容:

Welcome to the profile statistics browser.
timeStats.profile% stats hello
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'hello'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10    0.000    0.000    1.001    0.100 timeFunctions.py:3(hello)

timeStats.profile% stats thankyou
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'thankyou'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      100    0.002    0.000    5.012    0.050 timeFunctions.py:7(thankyou)

这个虚拟示例并没有做太多事情,但可以让您了解可以做什么。这种方法最好的部分是我不必编辑任何现有代码即可获得这些数字,并且显然有助于分析。

解决方案 15:

使用分析器模块。它提供了非常详细的配置文件。

import profile
profile.run('main()')

它输出类似这样的内容:

          5 function calls in 0.047 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.047    0.047    0.047    0.047 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.047    0.047 profile:0(main())
        1    0.000    0.000    0.000    0.000 two_sum.py:2(twoSum)

我发现它非常有用。

解决方案 16:

(仅限 Ipython)您可以使用%timeit来测量平均处理时间:

def foo():
    print "hello"

进而:

%timeit foo()

结果如下:

10000 loops, best of 3: 27 µs per loop

解决方案 17:

这是一个返回“hh:mm:ss”字符串的微型计时器类:

class Timer:
  def __init__(self):
    self.start = time.time()

  def restart(self):
    self.start = time.time()

  def get_time_hhmmss(self):
    end = time.time()
    m, s = divmod(end - self.start, 60)
    h, m = divmod(m, 60)
    time_str = "%02d:%02d:%02d" % (h, m, s)
    return time_str

用法:

# Start timer
my_timer = Timer()

# ... do something

# Get time string:
time_hhmmss = my_timer.get_time_hhmmss()
print("Time elapsed: %s" % time_hhmmss )

# ... use the timer again
my_timer.restart()

# ... do something

# Get time:
time_hhmmss = my_timer.get_time_hhmmss()

# ... etc

解决方案 18:

如果您希望能够方便地对函数进行计时,则可以使用一个简单的装饰器:

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        original_return_val = func(*args, **kwargs)
        end = time.perf_counter()
        print("time elapsed in ", func.__name__, ": ", end - start, sep='')
        return original_return_val

    return wrapper

您可以在想要计时的函数上使用它,如下所示:

@timing_decorator
def function_to_time():
    time.sleep(1)

function_to_time()

每当您调用时function_to_time,它都会打印花费的时间以及正在计时的函数的名称。

解决方案 19:

以下是使用以下方法得到的答案:

  • 简洁的上下文管理器来计时代码片段

  • time.perf_counter()计算时间增量。它应该是首选,因为它不可调整(系统管理员和守护进程都不能更改其值),与time.time()(参见文档)相反

import time
from collections.abc import Iterator
from contextlib import contextmanager

@contextmanager
def time_it() -> Iterator[None]:
    tic: float = time.perf_counter()
    try:
        yield
    finally:
        toc: float = time.perf_counter()
        print(f"Computation time = {1000*(toc - tic):.3f}ms")

如何使用它的一个例子:

# Example: vector dot product computation
with time_it():
    A = B = range(1_000_000)
    dot = sum(a*b for a,b in zip(A,B))
# Computation time = 95.353ms

附录

import time

# to check adjustability
assert time.get_clock_info('time').adjustable
assert time.get_clock_info('perf_counter').adjustable is False

解决方案 20:

我喜欢它简单(python 3):

from timeit import timeit

timeit(lambda: print("hello"))

单次执行的输出以微秒为单位:

2.430883963010274

解释:timeit 默认执行匿名函数100 万次,结果以秒为单位。因此,单次执行的结果相同,但平均以微秒为单位。


对于缓慢的操作,请添加较少的迭代次数,否则您可能会等待永远:

import time

timeit(lambda: time.sleep(1.5), number=1)

输出总是以为单位的总迭代次数

1.5015795179999714

解决方案 21:

要了解每个函数的递归调用,请执行以下操作:

%load_ext snakeviz
%%snakeviz

它只需要Jupyter 笔记本中的这两行代码,就可以生成一个漂亮的交互式图表。例如:

在此处输入图片描述

以下是代码。同样,以 开头的两行%是使用 snakeviz 所需的唯一额外代码行:

# !pip install snakeviz
%load_ext snakeviz
import glob
import hashlib

%%snakeviz

files = glob.glob('*.txt')
def print_files_hashed(files):
    for file in files:
        with open(file) as f:
            print(hashlib.md5(f.read().encode('utf-8')).hexdigest())
print_files_hashed(files)

似乎也可以在笔记本之外运行 snakeviz。更多信息请参阅snakeviz 网站。

解决方案 22:

还有一种使用timeit 的方法:

from timeit import timeit

def func():
    return 1 + 1

time = timeit(func, number=1)
print(time)

解决方案 23:

如何测量两个操作之间的时间。比较两个操作的时间。

import time

b = (123*321)*123
t1 = time.time()

c = ((9999^123)*321)^123
t2 = time.time()

print(t2-t1)

7.987022399902344e-05

解决方案 24:

这是一个有详细文档和完整类型提示的装饰器,我将其用作通用实用程序:

from functools import wraps
from time import perf_counter
from typing import Any, Callable, Optional, TypeVar, cast

F = TypeVar("F", bound=Callable[..., Any])


def timer(prefix: Optional[str] = None, precision: int = 6) -> Callable[[F], F]:
    """Use as a decorator to time the execution of any function.

    Args:
        prefix: String to print before the time taken.
            Default is the name of the function.
        precision: How many decimals to include in the seconds value.

    Examples:
        >>> @timer()
        ... def foo(x):
        ...     return x
        >>> foo(123)
        foo: 0.000...s
        123
        >>> @timer("Time taken: ", 2)
        ... def foo(x):
        ...     return x
        >>> foo(123)
        Time taken: 0.00s
        123

    """
    def decorator(func: F) -> F:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            nonlocal prefix
            prefix = prefix if prefix is not None else f"{func.__name__}: "
            start = perf_counter()
            result = func(*args, **kwargs)
            end = perf_counter()
            print(f"{prefix}{end - start:.{precision}f}s")
            return result
        return cast(F, wrapper)
    return decorator

使用示例:

from timer import timer


@timer(precision=9)
def takes_long(x: int) -> bool:
    return x in (i for i in range(x + 1))


result = takes_long(10**8)
print(result)

输出:

takes_long: 4.942629056s
True

可以使用以下方法检查文档测试:

$ python3 -m doctest --verbose -o=ELLIPSIS timer.py

类型提示如下:

$ mypy timer.py

解决方案 25:

有点太晚了,但也许对某些人来说有用。我认为这是一种非常干净的方法。

import time

def timed(fun, *args):
    s = time.time()
    r = fun(*args)
    print('{} execution took {} seconds.'.format(fun.__name__, time.time()-s))
    return(r)

timed(print, "Hello")

请记住,“print”是 Python 3 中的函数,而不是 Python 2.7 中的函数。但是,它可以与任何其他函数一起使用。干杯!

解决方案 26:

您可以使用 timeit。

下面是一个如何使用 Python REPL 测试接受参数的 naive_func 的示例:

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161  

如果函数没有任何参数,则不需要包装函数。

解决方案 27:

print_elapsed_time 函数如下

def print_elapsed_time(prefix=''):
    e_time = time.time()
    if not hasattr(print_elapsed_time, 's_time'):
        print_elapsed_time.s_time = e_time
    else:
        print(f'{prefix} elapsed time: {e_time - print_elapsed_time.s_time:.2f} sec')
        print_elapsed_time.s_time = e_time

以这种方式使用

print_elapsed_time()
.... heavy jobs ...
print_elapsed_time('after heavy jobs')
.... tons of jobs ...
print_elapsed_time('after tons of jobs')

结果是

after heavy jobs elapsed time: 0.39 sec
after tons of jobs elapsed time: 0.60 sec  

这个函数的优点和缺点是你不需要传递开始时间

解决方案 28:

我们还可以将时间转换为人类可读的时间。

import time, datetime

start = time.clock()

def num_multi1(max):
    result = 0
    for num in range(0, 1000):
        if (num % 3 == 0 or num % 5 == 0):
            result += num

    print "Sum is %d " % result

num_multi1(1000)

end = time.clock()
value = end - start
timestamp = datetime.datetime.fromtimestamp(value)
print timestamp.strftime('%Y-%m-%d %H:%M:%S')

解决方案 29:

尽管问题中没有严格要求,但通常情况下,您需要一种简单、统一的方法来逐步测量几行代码之间经过的时间。

如果您使用的是 Python 3.8 或更高版本,则可以使用赋值表达式(又名海象运算符)以相当优雅的方式实现这一点:

import time

start, times = time.perf_counter(), {}

print("hello")
times["print"] = -start + (start := time.perf_counter())

time.sleep(1.42)
times["sleep"] = -start + (start := time.perf_counter())

a = [n**2 for n in range(10000)]
times["pow"] = -start + (start := time.perf_counter())

print(times)

=>

{'print': 2.193450927734375e-05, 'sleep': 1.4210970401763916, 'power': 0.005671024322509766}

解决方案 30:

我为此创建了一个库,如果你想测量一个函数,你可以这样做


from pythonbenchmark import compare, measure
import time

a,b,c,d,e = 10,10,10,10,10
something = [a,b,c,d,e]

@measure
def myFunction(something):
    time.sleep(0.4)

@measure
def myOptimizedFunction(something):
    time.sleep(0.2)

myFunction(input)
myOptimizedFunction(input)

https://github.com/Karlheinzniebuhr/pythonbenchmark

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用