Измерить время, прошедшее в 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)

Преимущества использования этого подхода вместо других:

  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. Сохраните названия вашего 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 счетчика перфорирования), потому что

  1. timeit выбирает лучший таймер, доступный в вашей версии ОС и Python.
  2. 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

преимущества

Есть несколько полуобеспеченных версий, поэтому я хочу отметить несколько основных моментов:

  1. Используйте таймер из timeit вместо time.time по причинам, описанным ранее.
  2. Отключить GC во время синхронизации.
  3. Декоратор принимает функции с именованными или безымянными параметрами.
  4. Возможность отключить печать в блоке синхронизации (используйте with utils.MeasureBlockTime() as t а потом t.elapsed).
  5. Возможность держать 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)

https://github.com/Karlheinzniebuhr/pythonbenchmark

Другие вопросы по тегам