Почему python для петель настолько нелинейный для больших входов?
Я сравнивал некоторые коды python, я заметил что-то странное. Я использовал следующую функцию, чтобы измерить, как быстро потребовалось перебирать пустой цикл:
def f(n):
t1 = time.time()
for i in range(n):
pass
print(time.time() - t1)
f(10**6)
печатает около 0.035
, f(10**7)
около 0.35
, f(10**8)
около 3.5
и f(10**9)
около 35
. Но f(10**10)
? Хорошо над 2000
. Это конечно неожиданно. Зачем потребовалось бы в 60 раз больше времени для повторения в 10 раз больше элементов? Что с питоном для циклов, который вызывает это? Является ли это специфичным для python, или это происходит на многих языках?
Ответы
Ответ 1
Когда вы выходите выше 10^9
, вы получаете из 32-битного целочисленного диапазона. Python3 затем прозрачно перемещает вас на произвольные целые числа точности, которые гораздо медленнее выделять и использовать.
В целом работа с такими большими номерами является одной из областей, где Python3 намного медленнее, чем Python2 (который, по крайней мере, имел бы быстрые 64-битные целые числа во многих системах). С другой стороны, это упрощает использование python с меньшими ошибками overflow.
Ответ 2
Некоторые точные тайминги, использующие timeit
, показывают, что время фактически приблизительно увеличивается в соответствии с размером ввода, поэтому ваши тайминги выглядят довольно далеко:
In [2]: for n in [10**6,10**7,10**8,10**9,10**10]:
% timeit f(n)
...:
10 loops, best of 3: 22.8 ms per loop
1 loops, best of 3: 226 ms per loop # roughly ten times previous
1 loops, best of 3: 2.26 s per loop # roughly ten times previous
1 loops, best of 3: 23.3 s per loop # roughly ten times previous
1 loops, best of 3: 4min 18s per loop # roughly ten times previous
Используя xrange и python2, мы видим, что отношение примерно одинаковое, очевидно, что python2 намного быстрее в целом из-за того, что python3 int был заменен на long:
In [5]: for n in [10**6,10**7,10**8,10**9,10**10]:
% timeit f(n)
...:
100 loops, best of 3: 11.3 ms per loop
10 loops, best of 3: 113 ms per loop
1 loops, best of 3: 1.13 s per loop
1 loops, best of 3: 11.4 s per loop
1 loops, best of 3: 1min 56s per loop
Фактическое различие в времени выполнения, по-видимому, больше связано с размером окна длиной, а не напрямую связано с python 3. Разница незначительна при использовании unix, которая обрабатывает longs намного по-разному для окон, так что это проблема с конкретной платформой, если не больше, чем на python.