问题:如何在Python中测量经过时间?
我想要的是开始在我的代码中的某个地方开始计时,然后获取经过的时间,以衡量执行少量功能所花费的时间。我认为我使用的timeit模块错误,但是文档对我来说却很混乱。
import timeit
start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)
回答 0
如果您只想测量两点之间经过的挂钟时间,则可以使用 time.time()
:
import time
start = time.time()
print("hello")
end = time.time()
print(end - start)
这给出了执行时间(以秒为单位)。
自3.3起,另一个选择可能是使用perf_counter
或process_time
,具体取决于您的要求。在3.3之前,建议使用time.clock
(感谢Amber)。但是,目前不推荐使用:
在Unix上,以秒为单位返回当前处理器时间,以浮点数表示。精度,实际上是“处理器时间”含义的确切定义,取决于同名C函数的精度。
在Windows上,基于Win32函数,此函数返回自第一次调用此函数以来经过的时间(以秒为单位),以浮点数表示。
QueryPerformanceCounter()
。分辨率通常优于一微秒。从版本3.3开始不推荐使用:此功能的行为取决于平台:根据需要,使用
perf_counter()
或process_time()
相反,以具有明确定义的行为。
回答 1
使用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()-准确性?
也可以看看:
回答 2
仅限Python 3:
由于从Python 3.3开始不推荐使用 time.clock(),因此您将希望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
将不包括睡眠期间经过的时间。
回答 3
有了您想计时的功能,
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.time
或time.clock
(天真)比较功能的速度。他们可能会产生误导性的结果。
回答 4
使用上下文管理器执行此操作很有趣,该上下文管理器会自动记住进入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秒)。
回答 5
以秒为单位的测量时间:
from timeit import default_timer as timer
from datetime import timedelta
start = timer()
end = timer()
print(timedelta(seconds=end-start))
输出:
0:00:01.946339
回答 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
回答 7
这是执行此操作的另一种方法:
>> 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页面。
回答 8
这是我在这里经过许多不错的回答以及其他几篇文章后的发现。
首先,如果您在timeit
和之间进行辩论time.time
,则timeit
有两个优点:
timeit
选择操作系统和Python版本上可用的最佳计时器。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, no_print=False, disable_gc=False):
@wraps(f)
def _wrapper(*args, **kwargs):
gcold = gc.isenabled()
if disable_gc:
gc.disable()
start_time = timeit.default_timer()
try:
result = f(*args, **kwargs)
finally:
elapsed = timeit.default_timer() - start_time
if disable_gc and gcold:
gc.enable()
if not no_print:
print('"{}": {}s'.format(f.__name__, elapsed))
return result
return _wrapper
class MeasureBlockTime:
def __init__(self,name="(block)", no_print=False, disable_gc=False):
self.name = name
self.no_print = no_print
self.disable_gc = disable_gc
def __enter__(self):
self.gcold = gc.isenabled()
if self.disable_gc:
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
块中:
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
优点:
有几个半支持的版本,所以我想指出一些重点:
- 出于前面所述的原因,请使用timeit中的timer代替time.time。
- 如果需要,可以在计时期间禁用GC。
- 装饰器接受带有已命名或未命名参数的函数。
- 能够按块定时禁用打印(先使用
with utils.MeasureBlockTime() as t
,然后再使用t.elapsed
)。 - 能够为块定时保持启用gc的能力。
回答 9
使用 time.time
度量执行可以为您提供命令的整体执行时间,包括计算机上其他进程花费的运行时间。这是用户注意到的时间,但是如果您要比较不同的代码段/算法/函数/ …,则效果不佳。
有关更多信息timeit
:
如果您想对配置文件有更深入的了解:
更新:去年我大量使用了http://pythonhosted.org/line_profiler/,发现它非常有用,建议使用它代替Pythons profile模块。
回答 10
这是一个微小的计时器类,它返回“ 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
回答 11
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)添加任何代码,并且可以使用任何模块来完成此操作。
拥有stats文件后,您可以按以下方式运行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)
这个虚拟的例子并没有做太多,但是让您知道可以做什么。关于这种方法的最好之处在于,我不必编辑任何现有代码即可获得这些数字,并且显然可以帮助进行性能分析。
回答 12
这是另一个用于计时代码的上下文管理器-
用法:
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
Benchmark.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
回答 13
使用探查器模块。它提供了非常详细的配置文件。
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)
我发现它非常有用。
回答 14
我喜欢它简单(python 3):
from timeit import timeit
timeit(lambda: print("hello"))
单个执行的输出为微秒:
2.430883963010274
说明:timeit 默认执行匿名函数一百万次,结果以秒为单位。因此,单次执行的结果是相同的数量,但平均为微秒。
对于缓慢的操作添加较低数量的迭代,或者你可能会永远等待:
import time
timeit(lambda: time.sleep(1.5), number=1)
输出总是在秒总数目迭代:
1.5015795179999714
回答 15
(仅对于Ipython)可以使用%timeit来衡量平均处理时间:
def foo():
print "hello"
然后:
%timeit foo()
结果是这样的:
10000 loops, best of 3: 27 µs per loop
回答 16
使用timeit的另一种方法:
from timeit import timeit
def func():
return 1 + 1
time = timeit(func, number=1)
print(time)
回答 17
在python3上:
from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)
优雅而短暂。
回答 18
有点超级后来的反应,但也许对某人有用。我认为这是一种超级干净的方法。
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中的功能。但是,它可以与任何其他功能一起使用。干杯!
回答 19
您可以使用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
如果function没有任何参数,则不需要包装函数。
回答 20
我们还可以将时间转换为人类可以理解的时间。
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')
回答 21
我为此创建了一个库,如果您想测量一个函数,可以像这样做
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)
回答 22
要了解每个函数的递归调用,请执行以下操作:
%load_ext snakeviz
%%snakeviz
它只需在Jupyter笔记本中使用这两行代码,并生成一个漂亮的交互式图表。例如:
这是代码。再次,以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网站上有更多信息。
回答 23
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)
回答 24
这种独特的基于类的方法提供了可打印的字符串表示形式,可自定义的舍入功能,并且可以方便地访问作为字符串或浮点数的经过时间。它是使用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
回答 25
测量小代码段的执行时间。
时间单位:以秒为单位,以浮点数表示
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(垃圾收集器)作为设置字符串中的第一条语句重新启用。例如:
timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))',setup='gc.enable()')
源Python文档!
回答 26
如果您希望能够方便地计时功能,可以使用一个简单的装饰器:
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
,在您每次调用时,它都会打印花费了多长时间以及函数的名称。
回答 27
基于https://stackoverflow.com/a/30024601/5095636提供的contextmanager解决方案,以下是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
回答 28
我能想到的唯一方法是使用time.time()
。
import time
start = time.time()
sleep(5) #just to give it some delay to show it working
finish = time.time()
elapsed = finish - start
print(elapsed)
希望对您有所帮助。
回答 29
该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)