Возможно ли, чтобы функция python timeit когда-либо сообщала 0 как время выполнения?

Я работаю над проектом, в котором мы должны сравнить время выполнения нескольких алгоритмов сортировки (сортировка вставками, быстрая сортировка, сортировка слиянием и т. д.) для списков размером от 2 до 2 ^ 16. Мой инструктор указал, что, поскольку современные компьютеры очень быстры, время выполнения для «малых» размеров может вообще не регистрироваться и отображаться как 0. В качестве решения рекомендуется, чтобы для небольших экземпляров мы запускали алгоритм в дополнительном цикле и замерьте общее время выполнения, затем разделите это общее время на количество повторений цикла. Например,

while(repeat test 20 times) 
        while(execute algorithm 50 times)
             run algorithm

Я использую функцию timeit Python, чтобы выполнить это следующим образом.

    setup = '''
gc.enable()
import random
from __main__ import insertionSort
from __main__ import n #current instance size
from __main__ import s #random array
    '''
    average = sum(timeit.Timer('A=s[:]; insertionSort(A);',setup = setup).repeat(20,50))/20

Я делаю это для размеров от n до 32, после чего продолжаю тестирование, выполняя

average = sum(timeit.Timer('A=s[:]; insertionSort(A);',setup = setup).repeat(1,50))/50

Проблема, с которой я сталкиваюсь, заключается в том, что когда я превышаю 32, средние значения падают.

Averages for size 2^ 1
Insertion Sort Average:  0.00014180380003381288
Averages for size 2^ 2
Insertion Sort Average:  0.0002706763001697254
Averages for size 2^ 3
Insertion Sort Average:  0.0005087433502012573
Averages for size 2^ 4
Insertion Sort Average:  0.0018256775000736526
Averages for size 2^ 5
Insertion Sort Average:  0.006701907949900487
Averages for size 2^ 6
Insertion Sort Average:  0.00045550270002422624 #smaller average for larger instance?!

Итак, я думаю, мой вопрос: необходимо ли дополнительное повторение меньших экземпляров? Я пробовал синхронизировать однократные выполнения размера 2 и получил числа, очень близкие к 0 (x10^-6), но на самом деле так и не получил ноль.


person 84danie    schedule 28.04.2017    source источник
comment
По умолчанию большинство функций timeit запускают код 1 000 000 раз. Вот почему нет необходимости в дополнительном цикле. Кстати, вы переписали это с помощью 50 в вызове repeat(), чтобы зациклиться только 50 раз.   -  person Klaus D.    schedule 28.04.2017
comment
Да, я запускаю только 50 выполнений, потому что для выполнения каждого алгоритма с огромными значениями n требуется огромное количество времени. Вот почему я спрашиваю, должен ли я делать дополнительный цикл для небольших экземпляров, а также потому, что на самом деле он никогда не равен 0.   -  person 84danie    schedule 28.04.2017
comment
Проведите эксперимент: запустите print(time.time()) несколько раз в цикле. Посмотрите, получится ли у вас когда-нибудь точно такое же время. В противном случае даже измерение времени даст число › 0.   -  person Klaus D.    schedule 28.04.2017


Ответы (1)


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

>>> for n in range(9):
...   timeit.timeit("pass", number=10**n)/(10**n)
... 
3.0994415283203125e-06
1.9073486328125001e-07
5.0067901611328123e-08
3.6001205444335936e-08
3.3092498779296877e-08
3.4611225128173827e-08
1.6702890396118163e-08
1.2709689140319825e-08
1.1296820640563965e-08

Это предполагает накладные расходы ~ 3 микросекунды и время выполнения ~ 11 наносекунд.

person Prune    schedule 28.04.2017