Как измерить прошедшее время в Python?


1212

Я хочу начать отсчет времени где-то в моем коде, а затем получить прошедшее время, чтобы измерить время, необходимое для выполнения нескольких функций. Я думаю, что я использую модуль timeit неправильно, но документы меня просто сбивают с толку.

import timeit

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

Ответы:


1458

Если вы просто хотите измерить прошедшее время между двумя точками, вы можете использовать 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()вместо этого , в зависимости от ваших требований, чтобы иметь четко определенное поведение.


17
и для микросекунд, используйте datetime.time ()
инков

111
(Для измерения time.clock()производительности на самом деле предпочтительнее, поскольку на него нельзя вмешиваться, если системные часы портятся, но в .time()основном он выполняет ту же задачу.)
Янтарь

4
Я думаю, что python -mtimeit намного лучше, так как он выполняется больше раз, и он построен как собственный способ измерения времени в python
Visgean Skeloru

4
Есть хороший способ преобразования результирующего времени execturion в секундах в что-то вроде HH: MM :: SS?
Даниэль

12
@Danijel: print(timedelta(seconds=execution_time)). Хотя это отдельный вопрос.
JFS

690

Используйте 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 () - точность?

Смотрите также:


29
Отличный ответ - использование timeit даст гораздо более точные результаты, поскольку оно будет автоматически учитывать такие вещи, как сборка мусора и различия в ОС
lkgarrison

1
Это дает время в мс или секундах?
Кэти

3
@KhushbooTiwari за доли секунды.
JFS

5
Я думаю , что эта записка от официальных потребностей документации , которые будут добавленыdefault_timer() measurations can be affected by other programs running on the same machine, so the best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. The -r option is good for this; the default of 3 repetitions is probably enough in most cases. On Unix, you can use time.clock() to measure CPU time.
KGS

1
@ KGS: Измерение производительности очень сложно в тонком смысле (его легко ввести в заблуждение). Есть много других замечаний, которые могут быть актуальны здесь. Перейдите по ссылкам в ответе. Возможно, вас также заинтересует perfмодуль (не существовавший на момент ответа), который предоставляет тот же интерфейс, но иногда он отличается от timeitрешений, принимаемых модулем в отношении измерения производительности времени.
JFS

129

Только 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не будет включать время, прошедшее во время сна.


28
Используйтеtimeit.default_timer вместо time.perf_counter. Первый выберет подходящий таймер для измерения производительности времени, настроенной для вашей платформы и версии Python. process_time()делает не включает в себя время во время сна и , следовательно , он не подходит для измерения затраченного времени.
JFS

2
Я использую реализацию, предложенную Пьером, значения даны в секундах?
Уготчи

Этот ответ кажется не по теме (ну, вопрос не был очень конкретным). Существует два «временных» измерения: время между двумя точками на настенных часах, потребление процессором процессора.
Франклин

87

Учитывая функцию, которую вы хотели бы время,

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. Не помещайте операторы печати в функцию, которую вы хотите синхронизировать; в противном случае измеренное время будет зависеть от скорости терминала .


65

Это интересно сделать с помощью менеджера контекста, который автоматически запоминает время начала при входе в 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 секунд в этом игрушечном примере).


2
Другой пример менеджера контекста: dabeaz.blogspot.fr/2010/02/…
Жером

1
@ Прекрасный пример Жерома - я адаптировал его как другой ответ - stackoverflow.com/a/41408510/243392
Брайан Бернс

62

Время измерения в секундах:

from timeit import default_timer as timer
from datetime import timedelta

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

Выход :

0:00:01.946339

1
Это самый краткий ответ с самым чистым выводом.
Дэйв Лю

56

Я предпочитаю это. 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


Мне сказали, что timeit вычисляет время процессора, учитывает ли datetime время процессора? Это одно и то же?
Sreehari R

3
Таким образом, измерять истекшее время рискованно, поскольку datetime.now () может переключаться между двумя вызовами по причинам, таким как синхронизация сетевого времени, переключение летнего времени или переключение часов пользователем.
user1318499

45

Вот еще один способ сделать это:

>> 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 для более подробной информации.


13
Было бы хорошо объяснить преимущество использования этой библиотеки по сравнению с другими подходами.
ГВУ

Вложенная функциональность фактически нарушена. Я открыл проблему, описывающую, где проблема в коде, но репо не поддерживалось в течение года, поэтому я не ожидал изменений.
PetarMI

Я нахожу гнездо немного запутанным. Если бы мне пришлось столкнуться с тем, что скрыто t.tic()в коде, разработчик должен составить мысленный список того, где в этой серии я должен ожидать этого. Вы устанавливаете гнезда или просто несколько тиктоков?
ScottieB

1
@PetarMI: К вашему сведению, я только что исправил проблему с ttictoc. У меня был большой беспорядок, но теперь все должно быть хорошо.
Х. Санчес

33

Вот мои выводы, пройдя здесь много хороших ответов, а также несколько других статей.

Во-первых, если вы спорите между timeitи time.time, у timeitнего есть два преимущества:

  1. timeit выбирает лучший таймер, доступный в вашей версии ОС и Python.
  2. timeit отключает сборку мусора, однако это не то, что вы можете или не можете хотеть.

Теперь проблема в том, что timeitэто не так просто использовать, потому что он требует настройки, и все становится ужасно, когда у вас есть куча импорта. В идеале, вы просто хотите декоратор или использоватьwith блок и измерять время. К сожалению, для этого нет ничего встроенного, поэтому у вас есть два варианта:

Вариант 1. Использование библиотеки временных бюджетов

Timebudget является универсальной и очень простой библиотекой, которую можно использовать только в одной строке коды после установки пипа.

@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

Преимущества:

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

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

28

Использование time.timeдля измерения выполнения дает вам общее время выполнения ваших команд, включая время, затраченное другими процессами на вашем компьютере. Это время, которое пользователь замечает, но это не очень хорошо, если вы хотите сравнить разные фрагменты кода / алгоритмы / функции / ...

Больше информации о timeit:

Если вы хотите более глубокое понимание профилирования:

Обновление : я много использовал http://pythonhosted.org/line_profiler/ в течение последнего года и считаю его очень полезным и рекомендую использовать его вместо модуля профиля Pythons.


19

Вот небольшой класс таймера, который возвращает строку «чч: мм: сс»:

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

17

Модули 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)

Дурацкий пример мало что дает, но дает представление о том, что можно сделать. Лучшая часть этого подхода заключается в том, что мне не нужно редактировать существующий код, чтобы получить эти цифры и, очевидно, помочь с профилированием.


Все это хорошо, но AFAICT по-прежнему измеряет время процессора, а не время настенных часов.
ShreevatsaR

1
На самом деле есть некоторая путаница; Похоже, cProfile по умолчанию смотрит на часы. Я проголосовал за ваш ответ.
ShreevatsaR

К вашему сведению: Если вы получите, python -m pstats timeStats.profile ValueError: bad marshal data (unknown type code)проверьте свою версию Python, которую вы используете. Я получил это, когда я побежал python3 -m cProfile...и python -m pstats. Моя ошибка, но получила меня на секунду, поэтому я хотел поделиться don't forget consistency. =)
JayRizzo

17

Вот еще один менеджер контекста для временного кода -

Применение:

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


17

Используйте модуль профилировщика. Это дает очень подробный профиль.

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)

Я нашел это очень информативным.


1
Что такое main()? Было бы более полезно, если бы вы могли предоставить простой пример кода.
not2qubit

15

Мне нравится это просто (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

14

(Только для Ipython) вы можете использовать % timeit для измерения среднего времени обработки:

def foo():
    print "hello"

а потом:

%timeit foo()

результат примерно такой:

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

4
Стоит упомянуть, что можно передать флаги в% timeit, например, -n указывает, сколько раз код должен быть повторен.
гонщик

11

Еще один способ использовать timeit :

from timeit import timeit

def func():
    return 1 + 1

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

10

на python3:

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

элегантный и короткий.


что это? РС?
KIC

@ KIC Это в секундах.
Гимут

9

Вид супер позднего ответа, но, возможно, он кому-то нужен. Это способ сделать это, который я считаю очень чистым.

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. Тем не менее, он работает с любой другой функцией. Ура!


Как я могу печатать очень маленькие времена? Я вроде получаю 0.0sec всегда
Роуланд Мтетези

Вы можете превратить это в декоратор; это выглядит даже лучше для меня.
Даниил Москович

8

Вы можете использовать время.

Вот пример того, как проверить 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  

Вам не нужна функция-обертка, если у функции нет никаких параметров.


1
А lambdaбыло бы более кратким:print(timeit.timeit(lambda: naive_func(1_000), number=1_000_000))
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

7

Мы также можем преобразовать время в удобочитаемое время.

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')

6

Я сделал библиотеку для этого, если вы хотите измерить функцию, вы можете просто сделать это так


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


6

Чтобы получить рекурсивное представление о каждом вызове функции, выполните:

%load_ext snakeviz
%%snakeviz

Он просто берет эти 2 строки кода в записной книжке 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 .


2
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)

2

Этот уникальный подход на основе классов предлагает печатное представление строки, настраиваемое округление и удобный доступ к прошедшему времени в виде строки или числа с плавающей запятой. Он был разработан с 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

1

Измерьте время выполнения небольших фрагментов кода.

Единица времени : измеряется в секундах как число с плавающей точкой

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 !


1

Если вы хотите иметь возможность удобно распределять время по функциям, вы можете использовать простой декоратор:

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, он напечатает, сколько времени это заняло, и название функции, которая была синхронизирована.


1

на основе решения contextmanager, предоставленного https://stackoverflow.com/a/30024601/5095636 , ниже предлагается бесплатная лямбда-версия, поскольку flake8 предупреждает об использовании лямбды согласно E731 :

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

1

Самый простой способ рассчитать продолжительность операции:

import time

start_time = time.time()
print(time.ctime())

<operations, programs>

print('minutes: ',(time.time() - start_time)/60)

1

Вот довольно хорошо документированный и полностью подсказанный тип декоратор, который я использую как обычную утилиту:

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))


print(takes_long(10**8))

Вывод:

takes_long: 4.942629056s
True

Докуты можно проверить с помощью:

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

И тип намекает на:

$ mypy timer.py

1
Это супер круто, спасибо, что поделились. Я не сталкивался с библиотекой набора или нелокальным ключевым словом - интересно находить новые вещи для изучения. У меня проблемы с тем, чтобы обернуть голову вокруг этого Callable[[AnyF], AnyF]. Что это значит?
Дэнни

1
@Danny На вершине я определил псевдоним типа AnyFЗначить Callable[..., Any], так AnyFэто функция , которая может принимать любое количество аргументов типа и возвращение ничего. Так Callable[[AnyF], AnyF]расширится до Callable[[Callable[..., Any]], Callable[..., Any]]. Это тип возвращаемого значения timerили полный тип decorator. Это функция, которая принимает любую функцию в качестве единственного аргумента и возвращает любую функцию.
Руохола

1
Спасибо за объяснение! Я все еще пытаюсь полностью обернуть голову внутренностями декораторов. Это очень помогло!
Дэнни
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.