On the 16th of November 2022, Python 3.11 was released. One of the key highlights is that it is much faster. This article will put that into perspective by analysing Fibonacci algorithm across multiple releases.

For this particular case Python 3.11 is more than 2x faster than 3.10.

That being said the devil is in the details. Here is the code that we used to test:

def Fib(n):
    k = [1,1,1]
    if n==1 or n==2:
        return 1
    else:
        for idx in range(2,n):
            k[2] = k[1] + k[0]
            k[0] = k[1]
            k[1] = k[2]
        return k[2]

Granted that there are other ways of implementing Fibonacci, but this code does run 2 times fast than 3.10. To test this we used: pytest pytest-benchmark and nox

Pytest is a commonly used testing framework with a wide variety of plugins. The Pytest-benchmark is useful for performance benchmarking, enabling us to write a simple test:

def test_fib(benchmark):
    result = benchmark(Fib, 40)
    assert result == 102334155

There are several ways of running multiple versions of Python but we used nox, as it is easy to setup and does not need a cloud machine to test it. Please note for performance testing, it can be tricky if you do not use your own laptop. These tests were done on a MacBookPro, intel based processor – i5.

import nox

@nox.session(python=["3.7","3.8", "3.9","3.10", "3.11"])
def pythonRun(session):
    session.install("pytest", "pytest-benchmark")
    session.run("pytest", "Fib.py", "--benchmark-save=fib")

This short video shows how to setup testing multiple versions of python with nox.

1 minute video of using nox, pytest and pytest-benchmark to compare performance of Fibonacci algorithm.

It is true, that Python did get faster, and that will have implications in many projects, but in the technical computing world where many people use numpy and pandas this may not always be so clear as in this example. You could also get much different results by rewriting the code slightly differently. So here is the same problem written in Python 3.11 with different algorithms.

import math
import numpy as np
import pytest_benchmark


def myFib1(n):
    if n==1 or n==2:
        return 1
    else:
        return myFib1(n-1)+myFib1(n-2)

def myFib2(n):
    k = [1, 1]
    if n==1 or n==2:
        return 1
    else:
        for idx in range(2,n):
            k.append(k[idx-1]+k[idx-2])
        return k[len(k)-1]

def myFib3(n):
    k = [1, 1, 1]
    if n==1 or n==2:
        return 1
    else:
        for idx in range(2,n):
            k[2] = k[0] + k[1]
            k[0] = k[1]
            k[1] = k[2]
        return k[2]

def myFib4(n):
    sqrt = math.sqrt(5)
    return int((( (1 + sqrt) ** n - (1 - sqrt) ** n ) / ( 2 ** n * sqrt )))

def myFib5(n):
    sqrt = np.sqrt(5)
    return int((( (1 + sqrt) ** n - (1 - sqrt) ** n ) / ( 2 ** n * sqrt )))
AlgorithmMedian (ns)Times slower
myFib4540.75501.0
myFib51,931.33503.57
myFib32,691.39504.98
myFib22,877.56005.32
myFib110,888,798,281.9942>1000

This table shows that myFib2 is 5.32x slower than myFib4. Which means that in certain cases, changing the algorithm or implementation actually might have a bigger impact than python version.

The table below shows all the combinations of different versions of Python and different implementations.

Python VersionAlgorithmMedian (ns)Times slower
3.11myFib4545.90001.0
3.10myFib4757.53501.39
3.8myFib4888.45501.63
3.7myFib4905.09501.66
3.9myFib4966.34001.77
3.11myFib51,902.36503.48
3.10myFib52,123.56503.89
3.8myFib52,295.32504.20
3.9myFib52,372.33004.35
3.7myFib52,721.57504.99
3.11myFib22,799.37505.13
3.11myFib32,985.32005.57
3.10myFib25,139.50009.41
3.9myFib25,373.63509.84
3.8myFib25,388.96009.87
3.8myFib35,698.575010.44
3.9myFib35,828.660010.68
3.10my/Fib36,019.740011.03
3.7myFib26,026.565011.04
3.7myFib36,098.705011.17
3.11myFib110,593,028,328.0031>1000
3.10myFib119,697,730,521.0021>1000
3.8myFib121,099,857,967.0000>1000
3.9myFib122,114,287,559.0000>1000
3.7myFib124,175,061,539.0000>1000

When analysing these results, it is important to call out that performance can be achieved by changing the algorithm and the python version. We should in general avoid stating that Python 3.11 is X% faster than 3.10, as it does depend heavily on implementation. As you can see that the myFib4 in 3.10 is 34% slower than in 3.11, where myFib3 is twice as slow. One other clear conclusion is that Python is significantly slower when implementing recursive functions.

Please note that we are using the median in nanoseconds, as running multiple times the same algorithm, the median is in general the right way to measure performance. This article also did not compare OS or hardware architectures, but they too can influence the results.