Измерить время, прошедшее в Python?
Я хочу начать отсчет времени где-нибудь в моем коде, а затем получить прошедшее время, чтобы измерить время, необходимое для выполнения нескольких функций. Я думаю, что неправильно использую модуль time it, но документы меня просто сбивают с толку.
import timeit
start = timeit.timeit()
print "hello"
end = timeit.timeit()
print end - start
44 ответа
Если вы просто хотите измерить прошедшее время между двумя точками, вы можете использовать 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()
вместо этого, в зависимости от ваших требований, иметь четко определенное поведение.
Использование 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 () - точность?
Смотрите также:
Только 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
не будет включать время, прошедшее во время сна.
Время измерения в секундах:
from timeit import default_timer as timer
from datetime import timedelta
start = timer()
end = timer()
print(timedelta(seconds=end-start))
Учитывая функцию, которую вы хотели бы время,
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
(наивно) сравнивать скорость функций. Они могут дать ошибочные результаты.
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
Сейчас 2019 год. Давайте сделаем это кратким способом:
from ttictoc import TicToc
t = TicToc() ## TicToc("name")
t.tic();
# your code ...
t.toc();
print(t.elapsed)
Преимущества использования этого подхода вместо других:
- Краткий и прямой. программисту не требуется писать дополнительные переменные, такие как:
t1 = время ()
t2 = время ()
прошло = t2 - t1 - С вложенностью
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
- Сохраните названия вашего tictoc.
t = TicToc("save user")
print(t.name)
Пожалуйста, обратитесь к этой ссылке для более подробных инструкций.
Самый простой способ рассчитать продолжительность операции:
import time
start_time = time.monotonic()
print(time.ctime())
<operations, programs>
print('minutes: ',(time.monotonic() - start_time)/60)
Вот мои выводы, пройдя здесь много хороших ответов, а также несколько других статей.
Во-первых, вы всегда хотите использовать timeit
и не time.time
(и во многих случаях API счетчика перфорирования), потому что
timeit
выбирает лучший таймер, доступный в вашей версии ОС и Python.timeit
отключает сборку мусора, однако это не то, что вы можете или не можете хотеть.
Теперь проблема в том, что использовать его не так просто, потому что он нуждается в настройке и все становится ужасно, когда у вас есть куча импортов. В идеале вы просто хотите декоратор или использовать with
заблокировать и измерить время. К сожалению, для этого нет ничего встроенного, поэтому я создал ниже небольшой служебный модуль.
Служебный модуль Timing
# 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
блок:
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 вместо time.time по причинам, описанным ранее.
- Отключить GC во время синхронизации.
- Декоратор принимает функции с именованными или безымянными параметрами.
- Возможность отключить печать в блоке синхронизации (используйте
with utils.MeasureBlockTime() as t
а потомt.elapsed
). - Возможность держать gc включенным для синхронизации блока.
С помощью time.time
измерение выполнения дает вам общее время выполнения ваших команд, включая время выполнения, потраченное другими процессами на вашем компьютере. Это время, которое пользователь замечает, но это не хорошо, если вы хотите сравнить различные фрагменты кода / алгоритмы / функции /...
Больше информации о timeit
:
Если вы хотите глубже понять профилирование:
Обновление: я много использовал http://pythonhosted.org/line_profiler/ в течение прошлого года и считаю его очень полезным и рекомендую использовать его вместо модуля профиля Pythons.
на python3:
from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)
элегантный и короткий.
Используйте модуль профилировщика. Это дает очень подробный профиль.
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)
Я нашел это очень информативным.
Вот еще один менеджер контекста для временного кода -
Использование:
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
Вот небольшой класс таймера, который возвращает строку "чч: мм: сс":
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
(Только для Ipython) вы можете использовать %timeit для измерения среднего времени обработки:
def foo():
print "hello"
а потом:
%timeit foo()
результат примерно такой:
10000 loops, best of 3: 27 µs per loop
Модули 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)
Дурацкий пример мало что дает, но дает представление о том, что можно сделать. Лучшая часть этого подхода заключается в том, что мне не нужно редактировать существующий код, чтобы получить эти цифры и, очевидно, помочь с профилированием.
Мне нравится это просто (Python 3):
from timeit import timeit
timeit(lambda: print("hello"))
Выход составляет микросекунды за одно выполнение:
2.430883963010274
Объяснение: timeit по умолчанию выполняет анонимную функцию 1 миллион раз, а результат дается в секундах. Следовательно, результат за одно выполнение - то же самое количество, но в среднем в микросекундах.
Для медленных операций добавьте меньшее количество итераций, иначе вы можете ждать вечно:
import time
timeit(lambda: time.sleep(1.5), number=1)
Вывод всегда в секундах для общего количества итераций:
1.5015795179999714
Если вы хотите иметь возможность удобно синхронизировать функции, вы можете использовать простой декоратор:
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
, он напечатает, сколько времени это заняло, и имя функции, для которой требуется время.
Чтобы получить рекурсивное представление о каждом вызове функции, выполните:
%load_ext snakeviz
%%snakeviz
Он просто берет эти 2 строки кода в записной книжке 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.
Вот ответ с использованием:
- краткий контекстный менеджер для временных фрагментов кода
-
time.perf_counter()
вычислить временную дельту. Его следует предпочесть, так как он не регулируется (ни системный администратор, ни демон не могут изменить его значение), в отличие отtime.time()
(см. документ) - python 3.10+ (из-за набора текста, но его можно легко адаптировать к предыдущим версиям)
import time
from contextlib import contextmanager
from typing import Iterator
@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(1000000)
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
Еще один способ использовать timeit:
from timeit import timeit
def func():
return 1 + 1
time = timeit(func, number=1)
print(time)
Как измерить время между двумя операциями. Сравните время двух операций.
import time
b = (123*321)*123
t1 = time.time()
c = ((9999^123)*321)^123
t2 = time.time()
print(t2-t1)
7.987022399902344e-05
Вот довольно хорошо документированный декоратор с полным набором подсказок, который я использую как общую утилиту:
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
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")
Имейте в виду, что "печать" - это функция в Python 3, а не Python 2.7. Тем не менее, он работает с любой другой функцией. Ура!
Вы можете использовать время.
Вот пример того, как проверить naive_func, который принимает параметр, используя Python REPL:
>>> 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)