Як виміряти минулий час у Python?


1206

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

import timeit

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

Відповіді:


1452

Якщо ви просто хочете виміряти минулий час настінного годинника між двома точками, ви можете використовувати 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(дякую Янтарю ). Однак наразі застаріле:

У Unix поверніть поточний час процесора у вигляді числа з плаваючою комою, вираженого в секундах. Точність, а насправді саме визначення значення "процесорного часу", залежить від однойменної функції С.

У Windows ця функція повертає годинникові секунди, що минули з моменту першого виклику цієї функції, як номер з плаваючою комою на основі функції Win32 QueryPerformanceCounter(). Роздільна здатність, як правило, краще, ніж одна мікросекунда.

Застаріло з версії 3.3 : Поведінка цієї функції залежить від платформи: використовуйте perf_counter()або process_time()замість цього , залежно від ваших вимог, мати чітко визначену поведінку.


17
а для мікросекунд використовуйте datetime.time ()
інка

110
(Для вимірювання продуктивності, time.clock()насправді кращим, оскільки він не може бути перешкоди , якщо системний годинник зіпсується с, але .time()це в основному , досягти тієї ж мети.)
Amber

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

4
Чи є приємний спосіб перетворення отриманого часу виконання в секундах на щось на зразок HH: MM :: SS?
Даніель

12
@Danijel : print(timedelta(seconds=execution_time)). Хоча це окреме питання.
jfs

687

Використовуйте 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 () vs. time.time () - точність?

Дивись також:


28
Відмінна відповідь - використання 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
Я використовую реалізацію, запропоновану П'єром, чи значення задані в секундах?
ugotchi

Ця відповідь здається поза темою (ну, питання було не дуже конкретним). Існує два вимірювання "часу": час настінного годинника між двома точками, споживання процесора процесора.
Franklin

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

Ось код контекстного менеджера, достатній для виконання трюку:

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/…
Jérôme

1
@ Jérôme приємний приклад - я адаптував це як іншу відповідь - 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

Я вважаю за краще це. timeitdoc занадто заплутаний.

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 обчислює час процесора, чи враховує також timetime date: Це одне і те ж?
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
Було б добре пояснити перевагу використання цієї бібліотеки перед іншими підходами.
hlg

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

Я вважаю, що гніздування трохи заплутане. Якби я натрапивt.tic() похований в коді, розробник повинен дотримуватися ментального списку того, де в серії я повинен очікувати цього. Чи трапляєте ви себе, щоб налаштувати гнізда або просто кілька тиктоків?
ScottieB

1
@PetarMI: FYI, я просто вирішив проблему ttictoc. Досить безлад у мене був, але зараз має бути добре.
Х. Санчес

32

Ось мої висновки після перегляду багатьох хороших відповідей, а також кількох інших статей.

По-перше, якщо ви дискутуєте між timeitі time.time, timeitмає два переваги:

  1. timeit вибирає найкращий таймер, доступний для вашої ОС та версії Python.
  2. timeit вимикає збирання сміття, однак, це не те, що ви можете або не хочете.

Тепер проблема полягає в тому, що timeitце не так просто у використанні, оскільки він потребує налаштування, і все стає некрасивим, коли у вас є маса імпорту. В ідеалі ви просто хочете декоратор або використовуватиwith блок і вимірюєте час. На жаль, для цього немає нічого вбудованого, тому у вас є два варіанти:

Варіант 1: Використовуйте бібліотеку часових бюджетів

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

Переваги:

Існує кілька напівзахисних версій, що плавають навколо, тому я хочу зазначити кілька важливих моментів:

  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

Ось крихітний клас таймера, який повертає рядок "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

17

Модулі pyPhon 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

FYI: Якщо ви 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 мільйон разів , а результат надається в секундах . Тому результат за 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)


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

Майте на увазі, що "print" - це функція в Python 3, а не в Python 2.7. Однак він працює з будь-якою іншою функцією. Ура!


Як я можу друкувати дуже малі часи? Я наче завжди отримую 0,0сек.
Роуленд Мтетезі

Ви можете перетворити це на декоратор; мені це виглядає ще краще.
Данило Москович

8

Ви можете використовувати timeit.

Ось приклад того, як перевірити 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
A lambdaбуло б більш лаконічним:print(timeit.timeit(lambda: naive_func(1_000), number=1_000_000))
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

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 рядки коду в зошиті Юпітера , і він створює хорошу інтерактивну діаграму. Наприклад:

введіть тут опис зображення

Ось код. Знову ж таки, два рядки, що починаються з %- це єдині додаткові рядки коду, необхідні для використання зміївізу:

# !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 .


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]

Метод repe () - це зручність викликати 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 Docs !


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

на основі рішення контекстного менеджера, наданого 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

Ось досить добре задокументований та повністю натяканий декоратор, який я використовую як загальну утиліту:

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. Це функція, яка приймає будь-який тип функції як єдиний аргумент і повертає будь-який тип функції.
ruohola

1
Дякую за пояснення! Я все ще намагаюся повністю обернути голову навколо внутрішніх декораторів. Це дуже допомогло!
Денні

0

Єдиний спосіб, що я можу придумати - це використання 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)

Сподіваюся, що це допоможе.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.