Почему вычисление небольшой последовательности Фибоначчи с помощью интерпретатора Python выполняется быстрее, чем PyPy

#python #python-3.x #performance #pypy

Вопрос:

Я делал некоторые вычисления фибоначчи с помощью PyPy, сначала я начал с больших чисел, PyPy был немного быстрее, но с небольшими числами он дает почти такую же производительность, а в некоторых случаях обычный интерпретатор намного быстрее, чем pypy. Есть ли конкретная причина, почему?

 from time import time

def fibonacci(n):
    a, b = 0, 1
    for i in range(0, n):
        a, b = b, a   b
    return a
start = time()
result = fibonacci(5000)
end = time()
print(end-start) 
 

С небольшим числом, таким как 5000, Python на самом деле быстрее, чем PyPy;

 Python: 0.0006256103515625
PyPy: 0.0016071796417236328
 

Когда дело доходит до немного большего числа, такого как 1.000.000, PyPy работает быстрее, чем Python

 PyPy: 8.567905902862549
Python: 9.79963207244873
 

Но когда дело доходит до другого расчета, например:

 def sum_in_range(a,b):
    c = 0
    for i in range(1, a):
       for j in range(1, b):
          c  = i j
    return c

start = time()
result = sum_in_range(100000,100000)
end = time()
print(end-start)
 

PyPy в 60 раз быстрее Python

 PyPy: 0.1999509334564209
Python: 12.051937103271484
 

Комментарии:

1. Из данных по эффективности страницу ( pypy.org/performance.html ): «[…] JIT-компилятором как известно, не работает на […] очень короткий-запуск скриптов: как правило, если что-то работает ниже 0,2 с JIT-компилятором нет шансов» — ваш время выполнения слишком короткое данных по Джит, чтобы превзойти обычные с CPython

2. @Carcigenicate тоже пытался это timeit('fibonacci(100)','from __main__ import fibonacci') сделать, результат был почти таким же

3. @UnholySheep, но и с таким числом, как 500 000, python все равно выигрывает… оба они заканчиваются более чем за 2 секунды.

Ответ №1:

В дополнение к другим ответам: ваш пример фибоначчи работал бы примерно с той же скоростью, если бы он был написан на C, C#, на Python с JIT или без него, или где-либо еще. Это потому, что пример Фибоначчи дает экспоненциально большие числа. После нескольких итераций он тратит все время внутри библиотеки, обрабатывая все большие целые числа, и почти ничего за ее пределами.

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

Ответ №2:

Для инициализации JIT pypy требуется немного времени, и он будет лучше работать с повторными результатами. Чтобы проиллюстрировать немного другую версию кода:

 from __future__ import print_function
import sys
from datetime import datetime


def fibonacci(n):
    a, b = 0, 1
    for i in range(0, n):
        a, b = b, a   b
    return a

n = int(sys.argv[1])
runs = int(sys.argv[2])
durations = []
for i in range(runs):
    start = datetime.now()
    fibonacci(int(n))
    durations.append(datetime.now() - start)

durations.sort()

print('min:', durations[0])
print('median:', durations[int(runs / 2)])
print('max:', durations[-1])
 

И запуск его на нескольких версиях Python:

 # python2 --version
Python 2.7.18rc1
# python2 fib.py 5000 1000
min: 0:00:00.000303
median: 0:00:00.000307
max: 0:00:00.001273
# python2 fib.py 1000000 5
min: 0:00:05.711701
median: 0:00:05.782151
max: 0:00:05.850577

# python3 --version
Python 3.8.2
# python3 fib.py 5000 1000
min: 0:00:00.000305
median: 0:00:00.000309
max: 0:00:00.001254
# python3 fib.py 1000000 5
min: 0:00:05.796954
median: 0:00:05.825557
max: 0:00:05.841489

# pypy --version
Python 2.7.13 (7.3.1 dfsg-2, Apr 21 2020, 05:05:41)
[PyPy 7.3.1 with GCC 9.3.0]
# pypy fib.py 5000 1000
min: 0:00:00.000160
median: 0:00:00.000179
max: 0:00:00.002456
# pypy fib.py 1000000 5
min: 0:00:04.314290
median: 0:00:04.405727
max: 0:00:04.453215