Nano Hash - криптовалюты, майнинг, программирование

timeit против декоратора времени

Я пытаюсь рассчитать код. Сначала я использовал декоратор времени:

#!/usr/bin/env python

import time
from itertools import izip
from random import shuffle

def timing_val(func):
    def wrapper(*arg, **kw):
        '''source: http://www.daniweb.com/code/snippet368.html'''
        t1 = time.time()
        res = func(*arg, **kw)
        t2 = time.time()
        return (t2 - t1), res, func.__name__
    return wrapper

@timing_val
def time_izip(alist, n):
    i = iter(alist)
    return [x for x in izip(*[i] * n)]

@timing_val
def time_indexing(alist, n):
    return [alist[i:i + n] for i in range(0, len(alist), n)]

func_list = [locals()[key] for key in locals().keys()
             if callable(locals()[key]) and key.startswith('time')]
shuffle(func_list)  # Shuffle, just in case the order matters

alist = range(1000000)
times = []
for f in func_list:
    times.append(f(alist, 31))

times.sort(key=lambda x: x[0])
for (time, result, func_name) in times:
    print '%s took %0.3fms.' % (func_name, time * 1000.)

дает

% test.py
time_indexing took 73.230ms.
time_izip took 122.057ms.

А здесь я использую timeit:

%  python - m timeit - s '' 'alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]'
10 loops, best of 3:
    64 msec per loop
% python - m timeit - s 'from itertools import izip' 'alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]'
10 loops, best of 3:
    66.5 msec per loop

При использовании timeit результаты практически такие же, но при использовании декоратора времени кажется, что time_indexing быстрее, чем time_izip.

Чем объясняется эта разница?

Следует ли верить любому методу?

Если да, то какие?

26.10.2009

  • Между прочим, атрибут func_name ненадежно доступен для методов, только для функций, поэтому __name__ может быть более предпочтительным вместо этого. Попробуйте с time.sleep. 12.06.2014
  • @ A-B-B: Спасибо за исправление. 14.06.2014

Ответы:


1

Используйте timeit. Выполнение теста более одного раза дает мне гораздо лучшие результаты.

func_list=[locals()[key] for key in locals().keys() 
           if callable(locals()[key]) and key.startswith('time')]

alist=range(1000000)
times=[]
for f in func_list:
    n = 10
    times.append( min(  t for t,_,_ in (f(alist,31) for i in range(n)))) 

for (time,func_name) in zip(times, func_list):
    print '%s took %0.3fms.' % (func_name, time*1000.)

->

<function wrapper at 0x01FCB5F0> took 39.000ms.
<function wrapper at 0x01FCB670> took 41.000ms.
26.10.2009
  • Да, похоже, причина в этом. Спасибо! 26.10.2009
  • К вашему сведению, timeit также отключает сборку мусора на время теста. Это может быть еще одна проблема. 12.03.2010

  • 2

    Используйте упаковку из functools, чтобы улучшить ответ Мэтта Алкока.

    from functools import wraps
    from time import time
    
    def timing(f):
        @wraps(f)
        def wrap(*args, **kw):
            ts = time()
            result = f(*args, **kw)
            te = time()
            print 'func:%r args:[%r, %r] took: %2.4f sec' % \
              (f.__name__, args, kw, te-ts)
            return result
        return wrap
    

    В примере:

    @timing
    def f(a):
        for _ in range(a):
            i = 0
        return -1
    

    Вызов метода f, заключенного в @timing:

    func:'f' args:[(100000000,), {}] took: 14.2240 sec
    f(100000000)
    

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

    02.01.2015
  • Я не понимаю, какие дополнительные функциональные обертки здесь добавляют. Не могли бы вы подробнее рассказать об этом? 31.01.2019
  • wraps копирует метаданные о внутренней функции во внешнюю функцию. Без него украшенный функциональный объект будет ссылаться на оболочку, а не на внутреннюю функцию. Это проблема только при использовании инструментов, использующих самоанализ, таких как отладчики. Например, если мы вызвали help для декорированной функции без wraps, помощь была бы в декораторе, а не во внутренней функции. 27.02.2020
  • Однако в случае измерения таймингов на самом деле проблем не возникнет, поэтому я не понимаю, почему это должно быть применимо в этом случае. Оболочка не будет частью производственного кода. 22.10.2020

  • 3

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

    import time
    
    def timeit(f):
    
        def timed(*args, **kw):
    
            ts = time.time()
            result = f(*args, **kw)
            te = time.time()
    
            print 'func:%r args:[%r, %r] took: %2.4f sec' % \
              (f.__name__, args, kw, te-ts)
            return result
    
        return timed
    

    Использовать декоратор просто, либо использовать аннотации.

    @timeit
    def compute_magic(n):
         #function definition
         #....
    

    Или измените псевдоним функции, на которую вы хотите рассчитать время.

    compute_magic = timeit(compute_magic)
    
    28.02.2013
  • Я считаю, что использование здесь functools.wraps было бы небольшим улучшением 23.08.2014
  • Из любопытства был скопирован этот ответ отсюда ?: andreas-jung.com/contents/ 23.03.2016
  • Я думаю, что совершенно нормально ссылаться на код в другом месте на Stackoverlow. Я не вижу проблем с этим @emschorsch 17.03.2018

  • 4

    Я устал от from __main__ import foo, теперь используйте это - для простых аргументов, для которых работает% r, а не в Ipython.
    (Почему timeit работает только со строками, а не с преобразователями / замыканиями, т.е. timefunc (f, произвольные аргументы) ?)

    
    import timeit
    
    def timef( funcname, *args, **kwargs ):
        """ timeit a func with args, e.g.
                for window in ( 3, 31, 63, 127, 255 ):
                    timef( "filter", window, 0 )
        This doesn't work in ipython;
        see Martelli, "ipython plays weird tricks with __main__" in Stackoverflow        
        """
        argstr = ", ".join([ "%r" % a for a in args]) if args  else ""
        kwargstr = ", ".join([ "%s=%r" % (k,v) for k,v in kwargs.items()]) \
            if kwargs  else ""
        comma = ", " if (argstr and kwargstr)  else ""
        fargs = "%s(%s%s%s)" % (funcname, argstr, comma, kwargstr)
            # print "test timef:", fargs
        t = timeit.Timer( fargs, "from __main__ import %s" % funcname )
        ntime = 3
        print "%.0f usec %s" % (t.timeit( ntime ) * 1e6 / ntime, fargs)
    
    #...............................................................................
    if __name__ == "__main__":
        def f( *args, **kwargs ):
            pass
    
        try:
            from __main__ import f
        except:
            print "ipython plays weird tricks with __main__, timef won't work"
        timef( "f")
        timef( "f", 1 )
        timef( "f", """ a b """ )
        timef( "f", 1, 2 )
        timef( "f", x=3 )
        timef( "f", x=3 )
        timef( "f", 1, 2, x=3, y=4 )
    

    Добавлено: см. Также «ipython играет странные трюки с main», Мартелли в running-doctests-through-ipython < / а>

    27.10.2009
  • Спасибо! Это, безусловно, упрощает перенос функций в timeit. Вы можете опустить _1 _, _ 2 _, _ 3_, если используете fargs='%s(*%s,**%s)'%(funcname,args,kwargs), но, возможно, это затруднит чтение фаргов. 28.10.2009

  • 5

    Это тот тип потребностей, о котором вы молитесь, чтобы библиотека предоставила портативное решение - СУХОЕ! К счастью, funcy.log_durations приходит к ответу.

    Пример скопирован из документации:

    @log_durations(logging.info)
    def do_hard_work(n):
        samples = range(n)
        # ...
    
    # 121 ms in do_hard_work(10)
    # 143 ms in do_hard_work(11)
    # ...
    

    Просмотрите документацию по funcy, чтобы узнать о других вариантах, таких как различные аргументы ключевого слова и @log_iter_durations.

    24.01.2020

    6

    Вдохновленный ответом Мики Смита, я вместо этого сделал прямую печать (и не использовал модуль ведения журнала).

    Ниже удобно использовать в Google Colab.

    # pip install funcy
    from funcy import print_durations
    
    @print_durations()
    def myfunc(n=0):
      for i in range(n):
        pass
    
    myfunc(123)
    myfunc(123456789)
    
    # 5.48 mks in myfunc(123)
    # 3.37 s in myfunc(123456789)
    
    16.03.2020
  • Что это за агрегат мкс? 25.05.2021

  • 7

    Просто предположение, но может ли разница быть на порядок разницы в значениях range ()?

    Из вашего первоисточника:

    alist=range(1000000)
    

    Из вашего timeit примера:

    alist=range(100000)
    

    Как бы то ни было, вот результаты в моей системе с диапазоном, установленным на 1 миллион:

    $ python -V
    Python 2.6.4rc2
    
    $ python -m timeit -s 'from itertools import izip' 'alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]'
    10 loops, best of 3: 69.6 msec per loop
    
    $ python -m timeit -s '' 'alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]'
    10 loops, best of 3: 67.6 msec per loop
    

    Мне не удалось запустить другой ваш код, так как я не мог импортировать модуль "декоратор" в свою систему.


    Обновление. Я вижу то же несоответствие, что и вы, когда запускаю ваш код без участия декоратора.

    $ ./test.py
    time_indexing took 84.846ms.
    time_izip took 132.574ms.
    

    Спасибо, что разместили этот вопрос; Я кое-что узнал сегодня. знак равно

    26.10.2009
  • Я удалил модуль декоратора, поэтому мой код легче запускать. Не могли бы вы попробовать? Вы видите явную разницу в скорости при запуске скрипта? Кроме того, я изменил диапазон с 10 ^ 5 - ›10 ^ 6, так что сравнение более ровное. Спасибо. 26.10.2009
  • Обновлено, чего стоит, но похоже, что теперь вы получили ответ. Нет проблем. 26.10.2009

  • 8

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

    26.10.2009
  • Что насчет этого не кроссплатформенного? 22.10.2020
  • Новые материалы

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

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..