Подтвердить что ты не робот

Точная синхронизация функций в python

Я программирую в python на окнах и хочу точно измерить время, необходимое для запуска функции. Я написал функцию "time_it", которая выполняет другую функцию, запускает ее и возвращает время, затраченное на выполнение.

def time_it(f, *args):
    start = time.clock()
    f(*args)
    return (time.clock() - start)*1000

Я называю это 1000 раз и усредняет результат. (константа 1000 в конце - дать ответ в миллисекундах.)

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

Есть ли более стандартный или приемлемый способ сделать это?

Когда я изменил свою тестовую функцию, чтобы вызвать печать, чтобы она заняла больше времени, моя функция time_it возвращает среднее значение в 2,5 мс, тогда как cProfile.run('f()') возвращается и в среднем составляет 7,0 мс. Я полагал, что моя функция будет переоценивать время, если что-нибудь, что здесь происходит?

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

4b9b3361

Ответ 1

Вместо написания собственного кода профилирования я предлагаю вам проверить встроенные профилировщики Python (profile или cProfile, в зависимости от ваших потребностей): http://docs.python.org/library/profile.html

Ответ 2

Используйте timeit модуль из стандартной библиотеки Python.

Основное использование:

from timeit import Timer

# first argument is the code to be run, the second "setup" argument is only run once,
# and it not included in the execution time.
t = Timer("""x.index(123)""", setup="""x = range(1000)""")

print t.timeit() # prints float, for example 5.8254
# ..or..
print t.timeit(1000) # repeat 1000 times instead of the default 1million

Ответ 3

Вы можете создать декоратор "timeme" таким образом

import time                                                

def timeme(method):
    def wrapper(*args, **kw):
        startTime = int(round(time.time() * 1000))
        result = method(*args, **kw)
        endTime = int(round(time.time() * 1000))

        print(endTime - startTime,'ms')
        return result

    return wrapper

@timeme
def func1(a,b,c = 'c',sleep = 1):
    time.sleep(sleep)
    print(a,b,c)

func1('a','b','c',0)
func1('a','b','c',0.5)
func1('a','b','c',0.6)
func1('a','b','c',1)

Ответ 4

Этот код очень неточен

total= 0
for i in range(1000):
    start= time.clock()
    function()
    end= time.clock()
    total += end-start
time= total/1000

Этот код менее неточен

start= time.clock()
for i in range(1000):
    function()
end= time.clock()
time= (end-start)/1000

Очень неточно страдает от смещения измерения, если время выполнения функции близко к точности часов. Большинство измеренных времен - это просто случайные числа от 0 до нескольких тиков часов.

В зависимости от рабочей нагрузки вашей системы "время", которое вы наблюдаете от одной функции, может быть полностью артефактом планирования ОС и другими неконтролируемыми накладными расходами.

Вторая версия (менее неточная) имеет меньшую погрешность измерения. Если ваша функция очень быстрая, вам может потребоваться запустить ее 10 000 раз, чтобы отключить планирование ОС и другие накладные расходы.

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

Ответ 5

Если вы хотите, чтобы метод python, даже если блокировка, которую вы измеряете, может бросать, один хороший подход заключается в использовании оператора with. Определите класс Timer как

import time

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

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

import httplib

with Timer() as t:
    conn = httplib.HTTPConnection('google.com')
    conn.request('GET', '/')

print('Request took %.03f sec.' % t.interval)

__exit()__ будет вызываться, даже если запрашивается запрос на соединение. Точнее, вы бы использовали try finally, чтобы увидеть результат в случае его броска, например, с помощью

try:
    with Timer() as t:
        conn = httplib.HTTPConnection('google.com')
        conn.request('GET', '/')
finally:
    print('Request took %.03f sec.' % t.interval)

Подробнее здесь.

Ответ 6

Это аккуратно

from contextlib import contextmanager

import time
@contextmanager
def timeblock(label):
    start = time.clock()
    try:
        yield
    finally:
        end = time.clock()
        print ('{} : {}'.format(label, end - start))



with timeblock("just a test"):
            print "yippee"

Ответ 7

Как и @AlexMartelli ответ

import timeit
timeit.timeit(fun, number=10000)

может сделать трюк.