我想要的是在我的代码中的某个地方开始计算时间,然后获取经过的时间,以测量执行几个函数所花费的时间。我认为我使用错误的 timeit 模块,但文档只是让我感到困惑。
import timeit
start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)
我想要的是在我的代码中的某个地方开始计算时间,然后获取经过的时间,以测量执行几个函数所花费的时间。我认为我使用错误的 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_counter
or process_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_timer都是time.perf_counter() 。请参阅Python - time.clock() 与 time.time() - 准确性?
也可以看看:
由于自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
将不包括睡眠期间经过的时间。
以秒为单位测量时间:
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
给定一个你想要计时的函数,
测试.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.time
或time.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() )
这里的上下文管理器代码足以做到这一点:
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
doc 太混乱了。
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 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 页面。
计算操作持续时间的最简单方法:
import time
start_time = time.monotonic()
<operations, programs>
print('seconds: ', time.monotonic() - start_time)
官方文档在这里。
这是我在这里阅读了许多好的答案以及其他几篇文章后的发现。
首先,如果您在 和 之间进行辩论timeit
,time.time
则timeit
有两个优点:
timeit
选择您的操作系统和 Python 版本上可用的最佳计时器。timeit
禁用垃圾收集,但是,这不是您可能想要也可能不想要的东西。现在的问题是timeit
使用起来不是那么简单,因为它需要设置并且当你有一堆导入时事情会变得很难看。理想情况下,您只需要一个装饰器或使用with
块和测量时间。不幸的是,没有可用的内置功能,因此您有两种选择:
选项 1:使用 timebudget 库
timebudget是一个多功能且非常简单的库,您可以在 pip 安装后仅在一行代码中使用它。
@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()
优点:
有几个半支持版本浮动,所以我想指出几个亮点:
with timing.MeasureBlockTime() as t
然后t.elapsed
)。使用time.time
来衡量执行可以为您提供命令的总体执行时间,包括计算机上其他进程所花费的运行时间。这是用户注意到的时间,但如果您想比较不同的代码片段/算法/功能/ ...
更多信息timeit
:
如果您想更深入地了解分析:
更新:去年我使用了http://pythonhosted.org/line_profiler/很多,发现它很有帮助,建议使用它来代替 Python 的配置文件模块。
这是另一个用于计时代码的上下文管理器 -
用法:
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
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)
虚拟示例并没有做太多事情,但可以让您了解可以做什么。这种方法最好的部分是我不必编辑我现有的任何代码来获取这些数字,并且显然有助于分析。
这是一个返回“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
使用分析器模块。它提供了非常详细的配置文件。
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)
我发现它非常有用。
(仅限 Ipython)您可以使用%timeit来测量平均处理时间:
def foo():
print "hello"
接着:
%timeit foo()
结果是这样的:
10000 loops, best of 3: 27 µs per loop
我喜欢它简单(python 3):
from timeit import timeit
timeit(lambda: print("hello"))
单次执行的输出为微秒:
2.430883963010274
说明:timeit默认执行匿名函数100万次,结果以秒为单位。因此,1 次执行的结果是相同的数量,但平均以微秒为单位。
对于缓慢的操作,请添加较少的迭代次数,否则您可能会永远等待:
import time
timeit(lambda: time.sleep(1.5), number=1)
总迭代次数的输出总是以秒为单位:
1.5015795179999714
另一种使用timeit的方法:
from timeit import timeit
def func():
return 1 + 1
time = timeit(func, number=1)
print(time)
在 python3 上:
from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)
优雅而简短。
这是我用作通用实用程序的一个有据可查且完全类型提示的装饰器:
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
如何测量两次操作之间的时间。比较两次操作的时间。
import time
b = (123*321)*123
t1 = time.time()
c = ((9999^123)*321)^123
t2 = time.time()
print(t2-t1)
7.987022399902344e-05
%load_ext snakeviz
%%snakeviz
它只需要Jupyter notebook中的这两行代码,就可以生成一个漂亮的交互式图表。例如:
这是代码。同样,以 开头的 2 行%
代码是使用 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 网站上。
一种超级后来的回应,但也许它对某人有用。这是一种我认为非常干净的方法。
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 中的函数。但是,它适用于任何其他功能。干杯!
你可以使用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
如果函数没有任何参数,则不需要包装函数。
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
这个功能的优点和缺点是你不需要通过开始时间
尽管问题中没有严格要求,但通常情况下,您需要一种简单、统一的方法来增量测量几行代码之间的经过时间。
如果您使用的是 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}
我们还可以将时间转换为人类可读的时间。
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')
我为此做了一个库,如果你想测量一个函数,你可以这样做
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)
作为 lambda,获取经过的时间和时间戳:
import datetime
t_set = lambda: datetime.datetime.now().astimezone().replace(microsecond=0)
t_diff = lambda t: str(t_set() - t)
t_stamp = lambda t=None: str(t) if t else str(t_set())
在实践中:
>>>
>>> t_set()
datetime.datetime(2021, 3, 21, 1, 25, 17, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200), 'PDT'))
>>> t = t_set()
>>> t_diff(t)
'0:00:14'
>>> t_diff(t)
'0:00:23'
>>> t_stamp()
'2021-03-21 01:25:57-07:00'
>>> t_stamp(t)
'2021-03-21 01:25:22-07:00'
>>>
这种独特的基于类的方法提供了可打印的字符串表示、可自定义的舍入以及以字符串或浮点数形式方便地访问经过的时间。它是用 Python 3.7 开发的。
import datetime
import timeit
class Timer:
"""Measure time used."""
# Ref: https://stackoverflow.com/a/57931660/
def __init__(self, round_ndigits: int = 0):
self._round_ndigits = round_ndigits
self._start_time = timeit.default_timer()
def __call__(self) -> float:
return timeit.default_timer() - self._start_time
def __str__(self) -> str:
return str(datetime.timedelta(seconds=round(self(), self._round_ndigits)))
用法:
# Setup timer
>>> timer = Timer()
# Access as a string
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:03.
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:04.
# Access as a float
>>> timer()
6.841332235
>>> timer()
7.970274425
如果您希望能够方便地对函数进行计时,可以使用一个简单的装饰器:
def timing_decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
original_return_val = func(*args, **kwargs)
end = time.time()
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
,它都会打印花费了多长时间以及正在计时的函数的名称。
时间单位:以秒为单位的浮点数
import timeit
t = timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))')
t.timeit()
t.repeat()
>[1.2934070999999676, 1.3335035000000062, 1.422568500000125]
repeat() 方法方便多次调用 timeit() 并返回结果列表。
repeat(repeat=3)¶
有了这个列表,我们可以取所有时间的平均值。
默认情况下,timeit() 在计时期间会暂时关闭垃圾收集。time.Timer() 解决了这个问题。
优点:
timeit.Timer() 使独立计时更具可比性。gc 可能是被测函数性能的重要组成部分。如果是这样,gc(garbage collector) 可以作为设置字符串中的第一条语句重新启用。例如:
timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))',setup='gc.enable()')
import time
def getElapsedTime(startTime, units):
elapsedInSeconds = time.time() - startTime
if units == 'sec':
return elapsedInSeconds
if units == 'min':
return elapsedInSeconds/60
if units == 'hour':
return elapsedInSeconds/(60*60)
基于https://stackoverflow.com/a/30024601/5095636给出的上下文管理器解决方案,以下是 lambda 免费版本,因为 flake8 根据E731警告使用 lambda :
from contextlib import contextmanager
from timeit import default_timer
@contextmanager
def elapsed_timer():
start_time = default_timer()
class _Timer():
start = start_time
end = default_timer()
duration = end - start
yield _Timer
end_time = default_timer()
_Timer.end = end_time
_Timer.duration = end_time - start_time
测试:
from time import sleep
with elapsed_timer() as t:
print("start:", t.start)
sleep(1)
print("end:", t.end)
t.start
t.end
t.duration
该timeit
模块适用于为一小段 Python 代码计时。它至少可以以三种形式使用:
1-作为命令行模块
python2 -m timeit 'for i in xrange(10): oct(i)'
2- 对于短代码,将其作为参数传递。
import timeit
timeit.Timer('for i in xrange(10): oct(i)').timeit()
3-对于更长的代码:
import timeit
code_to_test = """
a = range(100000)
b = []
for i in a:
b.append(i*2)
"""
elapsed_time = timeit.timeit(code_to_test, number=100)/100
print(elapsed_time)
时间也可以通过 %timeit 魔术函数来测量,如下所示:
%timeit -t -n 1 print("hello")
n 1
仅用于运行功能 1 次。
除了%timeit
在ipython中,您还可以%%timeit
用于多行代码片段:
In [1]: %%timeit
...: complex_func()
...: 2 + 2 == 5
...:
...:
1 s ± 1.93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
也可以在jupyter notebook中以同样的方式使用,只需将魔法%%timeit
放在单元格的开头即可。