как вы измеряете время выполнения бинарного поиска python [duplicate]

Используйте delimiter.c_str() как разделитель :

copy(x.begin(),x.end(), ostream_iterator(s,delimiter.c_str()));

Таким образом, вы получаете const char*, указывающие на строку, что ostream_operator ожидает от ваш std::string.

256
задан BoshWash 1 July 2016 в 12:22
поделиться

12 ответов

Работа timeit - это запустить код установки один раз, а затем совершать повторные вызовы в ряд операторов. Итак, если вы хотите протестировать сортировку, требуется некоторая осторожность, чтобы один проход на месте сортировки не влиял на следующий проход с уже отсортированными данными (что, конечно же, сделало бы Timsort действительно блестят, потому что он лучше всего работает, когда данные уже частично упорядочены).

Вот пример того, как настроить тест для сортировки:

>>> import timeit

>>> setup = '''
import random

random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''

>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145

Обратите внимание, что серия операторов делает новую копию несортированных данных на каждом проходе.

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

Это мои советы по правильному использованию timeit. Надеюсь, это поможет: -)

210
ответ дан Fermi paradox 16 August 2018 в 02:44
поделиться
  • 1
    Разве не показывалось время, чтобы скопировать список в оператор a=s[:]? Что бы вы сделали, если бы хотели получить чисто время сортировки? – max 6 February 2012 в 10:33
  • 2
    Да, он включает в себя копию списка (что очень быстро по сравнению с самой сортировкой). Если вы не копируете, первый проход сортирует список, а оставшаяся передача не должна выполнять какую-либо работу. Если вы хотите узнать время только для сортировки, то запустите выше с и без timsort(a) и возьмите разницу :-) – Raymond Hettinger 7 February 2012 в 03:58
  • 3
    @max Используйте min (), а не среднее значение таймингов. Это рекомендация от меня, от Тима Петерса и от Гвидо ван Россума. Самое быстрое время представляет собой лучший алгоритм, который может выполнять при загрузке кешей, а система не занята другими задачами. Все тайминги шумные - самое быстрое время наименее шумное. Легко показать, что самые быстрые тайминги являются наиболее воспроизводимыми и, следовательно, наиболее полезными при синхронизации двух разных реализаций. – Raymond Hettinger 3 April 2012 в 20:43
  • 4
    Вы вычисляете средний (ну, общий, но эквивалентный) для 1000 входов; затем повторите 7 раз и возьмите minimum . Вам нужно усреднять более 1000 входов, потому что вам нужна средняя (не наилучшая) сложность алгоритма. Вам нужен минимум именно по той причине, которую вы дали. Я думал, что смогу улучшить свой подход, выбрав один вход, выполнив алгоритм 7 раз, взяв минимум; затем повторять его для 1000 различных входов и принимать среднее значение. Я не понял, что ваш .repeat(7,1000) уже делает это (используя одно и то же семя)! Таким образом, ваше решение идеально подходит IMO. – max 3 April 2012 в 22:04
  • 5
    Я могу только добавить, что то, как вы выделяете свой бюджет из 7000 исполнений (например, .repeat(7, 1000) vs. .repeat(2, 3500) vs .repeat(35, 200), должно зависеть от того, как ошибка из-за загрузки системы сравнивается с ошибкой из-за изменчивости ввода. В крайнем случае, если ваша система всегда находится под большой нагрузкой, и вы видите длинный тонкий хвост слева от распределения времени выполнения (когда вы его поймаете в редком состоянии бездействия), вы даже можете найти .repeat(7000,1) более полезным чем .repeat(7,1000), если вы не можете заплатить более 7000 прогонов. – max 3 April 2012 в 22:19

Встроенный модуль timeit лучше всего работает с командной строкой IPython.

В функции времени из модуля:

from timeit import default_timer as timer
import sys

def timefunc(func, *args, **kwargs):
    """Time a function. 

    args:
        iterations=3

    Usage example:
        timeit(myfunc, 1, b=2)
    """
    try:
        iterations = kwargs.pop('iterations')
    except KeyError:
        iterations = 3
    elapsed = sys.maxsize
    for _ in range(iterations):
        start = timer()
        result = func(*args, **kwargs)
        elapsed = min(timer() - start, elapsed)
    print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
    return result
0
ответ дан ChaimG 16 August 2018 в 02:44
поделиться
# Генерация целых чисел

def gen_prime(x):
    multiples = []
    results = []
    for i in range(2, x+1):
        if i not in multiples:
            results.append(i)
            for j in range(i*i, x+1, i):
                multiples.append(j)

    return results


import timeit

# Засекаем время

start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)

# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)
9
ответ дан David Webb 16 August 2018 в 02:44
поделиться

Это отлично работает:

  python -m timeit -c "$(cat file_name.py)"
5
ответ дан Ohad Rubin 16 August 2018 в 02:44
поделиться

для меня это самый быстрый способ:

import timeit
def foo():
    print("here is my code to time...")


timeit.timeit(stmt=foo, number=1234567)
7
ответ дан Rodrigo Laguna 16 August 2018 в 02:44
поделиться

позволяет установить один и тот же словарь в каждом из следующих и проверить время выполнения.

Аргумент настройки в основном настраивает словарь

. Номер предназначен для запуска кода 1000000 раз , Не настройка, а stmt

Когда вы запустите это, вы увидите, что индекс быстрее, чем get. Вы можете запустить его несколько раз, чтобы увидеть.

Код в основном пытается получить значение c в словаре.

import timeit

print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))

Вот мои результаты, ваши будут отличаться.

по индексу: 0.20900007452246427

по get: 0.54841166886888

3
ответ дан Stryker 16 August 2018 в 02:44
поделиться

Если вы хотите использовать timeit в интерактивном сеансе Python, есть два удобных варианта:

  1. Используйте оболочку IPython . Он имеет удобную специальную функцию %timeit:
    In [1]: def f(x):
       ...:     return x*x
       ...: 
    
    In [2]: %timeit for x in range(100): f(x)
    100000 loops, best of 3: 20.3 us per loop
    
  2. В стандартном интерпретаторе Python вы можете получить доступ к функциям и другим именам, которые вы определили ранее во время интерактивного сеанса, импортировав их из __main__ в настройке утверждение:
    >>> def f(x):
    ...     return x * x 
    ... 
    >>> import timeit
    >>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
                      number=100000)
    [2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
    
212
ответ дан Sven Marnach 16 August 2018 в 02:44
поделиться
  • 1
    +1 для отображения техники from __main__ import f. Я не думаю, что это так широко известно, как должно быть. Это полезно в таких случаях, когда вызывается функция или вызов метода. В других случаях (временная последовательность шагов) он менее полезен, поскольку он вводит служебные вызовы функций. – Raymond Hettinger 22 November 2011 в 04:30
  • 2
    +1 для IPython% magic – kmonsoor 26 January 2014 в 13:36
  • 3
    from __main__ import f. Это превосходно... – Irshad Bhat 22 December 2014 в 17:38
  • 4
    Вы можете просто сделать %timeit f(x) – qed 23 December 2014 в 16:55
  • 5
    Примечание: "import f & quot; setup делает доступ к f быстрым локальным чтением - что точно не отражает глобальный вызов функции (короткой быстрой функции) в типичном нормальном коде. В Py3.5 + могут поставляться реальные глобальные переменные: «Изменено в версии 3.5: добавлен параметр дополнительных глобальных переменных». Перед глобалями времени в модуле, где это неизбежно (что не имеет особого смысла). Вероятно, глобальные значения вызывающего кода (sys._getframe(N).f_globals) должны были быть по умолчанию с самого начала. – kxr 6 May 2017 в 08:15

просто передайте весь код в качестве аргумента timeit:

import timeit

print(timeit.timeit("""

limit = 10000
prime_list = [i for i in range(2, limit+1)]

for prime in prime_list:
    for elem in range(prime*2, max(prime_list)+1, prime):
        if elem in prime_list:
            prime_list.remove(elem)"""

, number=10))
1
ответ дан tryptofan 16 August 2018 в 02:44
поделиться

Я нахожу, что самый простой способ использовать timeit - из командной строки:

Учитывая test.py:

def InsertionSort(): ...
def TimSort(): ...

run timeit как это:

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
41
ответ дан unutbu 16 August 2018 в 02:44
поделиться

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

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

Итак, интерфейс командной строки:

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

Это довольно просто, eh?

Вы можете настроить файл:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

, который тоже полезен!

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

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

Это дает настройку

x = range(1000)
y = range(100)

и времени

sum(x)
min(y)

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

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

Это может занять несколько больше времени из-за множественных инициализаций, но обычно это не очень важно.


Но что если вы хотите использовать timeit внутри вашего модуля?

Ну, простой способ сделать:

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

, и это дает вам кумулятивное ( not минимум!) время для запуска этого количества раз.

Чтобы получить хороший анализ, используйте .repeat и возьмите минимум:

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

Обычно вы должны комбинировать это с functools.partial вместо lambda: ..., чтобы снизить накладные расходы. Таким образом, у вас может быть что-то вроде:

from functools import partial

def to_time(items):
    ...

test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)

# Divide by the number of repeats
time_taken = min(times) / 1000

Вы также можете сделать:

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

, который даст вам что-то ближе к интерфейсу из командной строки, но в гораздо менее прохладной манере. "from __main__ import ..." позволяет вам использовать код из вашего основного модуля внутри искусственной среды, созданной timeit.

Стоит отметить, что это удобная обертка для Timer(...).timeit(...), и поэтому она не особенно хороша в время. Я лично предпочитаю использовать Timer(...).repeat(...), как я показал выше.


Предупреждения

Есть несколько предостережений с timeit, которые находятся повсюду.

  • Накладные расходы не учитываются. Скажите, что хотите время x += 1, чтобы узнать, сколько времени занимает добавление:
    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop
    
    Ну, это не 0.0476 мкс. Вы только знаете, что это меньше , чем это. Вся ошибка положительная. Поэтому попробуйте найти чистые накладные расходы:
    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop
    
    Это хорошая 30% накладных расходов только с момента! Это может значительно исказить относительные тайминги. Но вы действительно заботились о добавлении таймингов; временные интервалы поиска для x также должны быть включены в накладные расходы:
    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop
    
    Разница не намного больше, но она есть.
  • Методы мутации опасны.
    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop
    
    Но это совершенно неверно! x - это пустой список после первой итерации. Вам нужно будет повторно инициализировать:
    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop
    
    Но тогда у вас много накладных расходов. Учтите это отдельно.
    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop
    
    Обратите внимание, что вычитание служебных данных здесь разумно только потому, что накладные расходы являются малой частью времени. Для вашего примера стоит отметить, что и Sorting Sort и Tim Sort имеют совершенно необычное временное поведение для уже отсортированных списков. Это означает, что вам понадобится random.shuffle между сортировками, если вы хотите избежать разрушения ваших таймингов.
105
ответ дан Veedrac 16 August 2018 в 02:44
поделиться

Пример использования интерпретатора 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                                                                                        
0
ответ дан Vlad Bezden 16 August 2018 в 02:44
поделиться

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

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
70
ответ дан zzart 16 August 2018 в 02:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: