Функція вимірювання часу Python


122

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

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed

Інструменти профілювання Python можуть показувати назви функцій та час, проведений у кожному з них. Читайте тут: docs.python.org/library/profile.html
дорожній

Краще використовувати timeitдля вимірювання. Це не ідеально, але він ударить вашим ударом далеко, і це набагато простіше у використанні, timeitніж вибивати щось краще.

Відповіді:


241

Перш за все, я настійно пропоную використовувати профайлер або принаймні використовувати timeit .

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

Пітон 2:

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
        return ret
    return wrap

А використання дуже просте, просто використовуйте декоратор @timing:

@timing
def do_work():
  #code

Пітон 3:

def timing(f):
    def wrap(*args, **kwargs):
        time1 = time.time()
        ret = f(*args, **kwargs)
        time2 = time.time()
        print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))

        return ret
    return wrap

Примітка. Я закликаю f.func_nameотримати ім'я функції у вигляді рядка (в Python 2) або f.__name__ в Python 3.


4
саме те, що я хочу :) ... але ви, хлопці, переконали мене використовувати
профілер

3
Схоже, це передбачає, що time.time () повідомляє про час у мікросекундах з епохи? У документації зазначено, що вона повідомляє про час у секундах docs.python.org/2/library/time.html#time.time .
Рахул-Джа

Це не може набути чинності після використання урожайності у функції. Як я ще можу використовувати цей метод і можу використовувати урожай?
jiamo

def timing (f): def wrap (* args, ** kwargs): time1 = time.time () ret = f (* args, ** kwargs) time2 = time.time () Функція друку% s займає% 0,3 f ms '% (f.func_name, (time2-time1) * 1000) return ret return wrap
Vivek Bagaria

1
який недолік написати це самостійно? Чи не зберігається список минулих часів та вивчається їх розповсюдження досить просто?
3pitt

51

Після гри з timeitмодулем мені не подобається його інтерфейс, який не такий елегантний порівняно з двома наступними методами.

Наступний код знаходиться в Python 3.

Декоративний метод

Це майже те саме з методом @ Майка. Тут я додаю kwargsі functoolsзагортаю, щоб було краще.

def timeit(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        elapsedTime = time.time() - startTime
        print('function [{}] finished in {} ms'.format(
            func.__name__, int(elapsedTime * 1000)))
    return newfunc

@timeit
def foobar():
    mike = Person()
    mike.think(30)

Метод контекстного менеджера

from contextlib import contextmanager

@contextmanager
def timeit_context(name):
    startTime = time.time()
    yield
    elapsedTime = time.time() - startTime
    print('[{}] finished in {} ms'.format(name, int(elapsedTime * 1000)))

Наприклад, ви можете використовувати його так:

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()

І код всередині withблоку буде приурочений.

Висновок

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

Наприклад, зараз у вас є

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Тепер ви хочете відстежити bigImage = ...лінію. Якщо ви зміните його на функцію, це буде:

images = get_images()
bitImage = None
@timeit
def foobar():
    nonlocal bigImage
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Виглядає не так чудово ... Що робити, якщо ви перебуваєте в Python 2, де немає nonlocalключового слова.

Натомість, тут добре підходить використання другого методу:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Цікавий внесок, однак я вважаю марним те, що в методі декоратора, який ви згадали, вам довелося змінити timeitінтерфейс і використовувати wraps()функцію functoolsмодуля. Я маю на увазі все, що зайвий код не потрібен.
Біллал Бегерадж

1
Потребиimport functools
Гійом Шевальє

1
Зауважте, що ваш декоратор втрачає повернене значення початкової функції
Марк Ван Даель

11

Я не бачу, в чому проблема з timeitмодулем. Це, мабуть, найпростіший спосіб зробити це.

import timeit
timeit.timeit(a, number=1)

Також можливо надіслати аргументи функціям. Все, що вам потрібно - це завершити свою функцію за допомогою декораторів. Більше пояснення тут: http://www.pythoncentral.io/time-a-python-function/

Єдиний випадок, коли вам може бути цікаво писати власні заяви про терміни, якщо ви хочете запустити функцію лише один раз, а також хочете отримати її повернене значення.

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


3
Надіслати аргументи функції за допомогою обгортки та декораторів? Чому ні timeit.timeit(lambda: func(a,b,c), number=1)? Я використовую це, коли роблю тести на гіпотетичне рішення в терміналі.
Джек

10

У Timeit є два великих недоліки: він не повертає значення повернення функції, і він використовує eval, що вимагає введення додаткового коду настройки для імпорту. Це вирішує обидві проблеми просто та елегантно:

def timed(f):
  start = time.time()
  ret = f()
  elapsed = time.time() - start
  return ret, elapsed

timed(lambda: database.foo.execute('select count(*) from source.apachelog'))
(<sqlalchemy.engine.result.ResultProxy object at 0x7fd6c20fc690>, 4.07547402381897)

Дякую! timeit не працює добре з Apache Spark, тому що вам доведеться імпортувати всі іскрові залежності, а хто хоче створити велику стару рядок, яка це робить? Це рішення набагато простіше і гнучкіше.
Павло

4

Існує простий інструмент для встановлення часу. https://github.com/RalphMao/PyTimer

Це може працювати як декоратор :

from pytimer import Timer
@Timer(average=False)      
def matmul(a,b, times=100):
    for i in range(times):
        np.dot(a,b)        

Вихід:

matmul:0.368434
matmul:2.839355

Він також може працювати як плагін-таймер з керуванням простором імен (корисно, якщо ви вставляєте його у функцію, яка має багато кодів, і її можна викликати деінде).

timer = Timer()                                           
def any_function():                                       
    timer.start()                                         

    for i in range(10):                                   

        timer.reset()                                     
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block1')                        

        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block2')                        
        np.dot(np.ones((100,1000)), np.zeros((1000,1000)))

    for j in range(20):                                   
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
    timer.summary()                                       

for i in range(2):                                        
    any_function()                                        

Вихід:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

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


3

Метод декоратора за допомогою бібліотеки декораторів Python:

import decorator

@decorator
def timing(func, *args, **kwargs):
    '''Function timing wrapper
        Example of using:
        ``@timing()``
    '''

    fn = '%s.%s' % (func.__module__, func.__name__)

    timer = Timer()
    with timer:
        ret = func(*args, **kwargs)

    log.info(u'%s - %0.3f sec' % (fn, timer.duration_in_seconds()))
    return ret

Переглянути публікацію в моєму блозі:

повідомлення в блозі mobilepro.pl

моя публікація в Google Plus


1

Мій спосіб зробити це:

from time import time

def printTime(start):
    end = time()
    duration = end - start
    if duration < 60:
        return "used: " + str(round(duration, 2)) + "s."
    else:
        mins = int(duration / 60)
        secs = round(duration % 60, 2)
        if mins < 60:
            return "used: " + str(mins) + "m " + str(secs) + "s."
        else:
            hours = int(duration / 3600)
            mins = mins % 60
            return "used: " + str(hours) + "h " + str(mins) + "m " + str(secs) + "s."

Встановіть змінну, як start = time()раніше, виконайте функцію / циклі таprintTime(start) відразу після блоку.

і ти отримав відповідь.

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