
Published 2022-12-29 00:57:54
Battle Python 3.10 vs Python 3.11
image: rawpixel.com
Introduction
This is a short, but fun post comparing Python 3.10 and 3.11 performances.
The quote from the official documentation:
"Python 3.11 is between 10-60% faster than Python 3.10. On average, we measured a 1.25x speedup on the standard benchmark suite".
We will need to ensure that this is correct. Not only that, but we also want to know how much faster 3.11 is, if at all. We will use some very simple benchmarking methods for this. Before we start, you will need to set up your local environment if you want to test it yourself.
Installation
The following needs to be done on your local machine:
- You can download versions 3.10 and 3.11 from the following location https://www.python.org/downloads/
- Install both versions to your machine
- Create a folder and install two virtual environments with different names
example:
# python3.11 -m venv venv_311
# python3.10 -m venv venv_310
# ls -l
Output:
venv_310
venv_311
Source Code
You can get the code used in this article from here:
https://github.com/devoriales/python/tree/main/battle_310_vs_311
How To Compare
We're going to write a function that uses recursion to calculate the n-th term of the Fibonacci sequence, which is defined as the sum of the previous two terms in the sequence. The Fibonacci sequence is a mathematical series that starts with 0 and 1, and each subsequent term is the sum of the previous two terms.
This function can be computationally intensive for large values of n
, because it requires multiple recursive calls to calculate the n-th term. For example, calculating the 40th term of the Fibonacci sequence requires over 10^18 recursive calls, which can take a significant amount of time to compute.
The Fibonacci function:
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
Let's throw in one more function that is computationally intensive.
The following function divides the input number by 2 as many times as possible and then divides it by odd numbers until it is reduced to 1. The prime factors are stored in a list and returned at the end. What we will do is, we will request the prime factorization of the Fibonacci number which is pretty mean to our computer.
This algorithm is relatively simple and easy to understand, but it can be computationally intensive for large input numbers because it performs a division for every potential prime factor.
def prime_factorization(n):
# initialize a list to store the prime factors
prime_factors = []
# Divide the number by 2 until it is reduced to 1
while n % 2 == 0:
prime_factors.append(2)
n = n // 2
# Divide the number by odd numbers until it is reduced to 1
for i in range(3, n + 1, 2):
while n % i == 0:
prime_factors.append(i)
n = n // i
The code below is the complete code. We will have a variable that defines how many rounds to run, and it seems to be getting really heavy the closer we get to round 40. So, let's be mean and set it to 45 😠. You might need to adjust this to suit your machine. In my case, the code is running on a pretty fast Apple Silicon CPU, but if you have a slower machine, you might need to lower it a little bit.
battle.py - The main python code
'''
devoriales.com
description: This is a battle between Python 3.10 and Python 3.11 to see which one is faster.
'''
# function that will compute squareroot of a number
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
def prime_factorization(n):
# initialize a list to store the prime factors
prime_factors = []
# Divide the number by 2 until it is reduced to 1
while n % 2 == 0:
prime_factors.append(2)
n = n // 2
# Divide the number by odd numbers until it is reduced to 1
for i in range(3, n + 1, 2):
while n % i == 0:
prime_factors.append(i)
n = n // i
# Return the list of prime factors
return prime_factors
if __name__ == '__main__': # main function that only runs when the file is executed, not imported
round = 45 # how many rounds to run
current_round = 1 # initialize the round number
for i in range(1, round, 1): # loop from 1 to 50
print(f"Round {current_round}:") # print the round number
print(prime_factorization(fibonacci(i))) # print the prime factorization of the fibonacci number
current_round += 1 # increment the round number
if current_round == round:
print("Done!")
We can try this code by running it from one of the virtual environments that you have created.
Output:
...
Round 42:
[2, 2, 2, 13, 29, 211, 421]
Round 43:
[433494437]
Round 44:
[3, 43, 89, 199, 307]
Done!
Bash Script Wrapper
To be able to run our Python code externally in two different virtual environments, I found it most convenient to execute the code from a bash script that is switching between the environments. We will also calculate the elapsed time and percentage for both runs and compare those two. For this, we have the bash code below.
wrapper.sh - running python code in two different virtual environments
#!/bin/bash
# devoriales.com, 2022
# wrapper script to run the battle of Python 3.10 and Python 3.11
echo "Battle of Python 3.10 and Python 3.11"
countdown=5
while [ $countdown -gt 0 ]
do
echo "Fight begins in $countdown"
sleep 1
countdown=$((countdown-1))
if [ $countdown -eq 0 ]
then
echo "Let's get ready to rumble!"
sleep 2
fi
done
# set Python version to 3.10
source venv_310/bin/activate
# print the python version
echo "Python version: $(python --version)"
start=$(date +%s)
# run the python script
python battle.py
end=$(date +%s)
runtime=$((end-start))
echo "Runtime: $runtime seconds"
# set Python version to 3.11
source venv_311/bin/activate
echo "Python version: $(python --version)"
start_311=$(date +%s)
python battle.py
end_311=$(date +%s)
runtime_311=$((end_311-start_311))
echo "Runtime: $runtime_311 seconds"
# compare the runtimes
if [ $runtime -lt $runtime_311 ]
then
echo "Python 3.10 is faster than Python 3.11 by $((runtime_311-runtime)) seconds"
echo "in percentage: $((runtime*100/runtime_311))%"
else
echo "Python 3.11 is faster than Python 3.10 by $((runtime-runtime_311)) seconds"
echo "in percentage: $((runtime_311*100/runtime))%"
fi
Output:
Python 3.11 is faster than Python 3.10 by 119 seconds
in percentage: 64%
We have a winner: Python 3.11 is indeed faster than 3.10, at least in this silly battle. Now, don't take this figure as precise. I've done some other benchmarking and came to the conclusion that, on average, Python 3.11 is about 20% faster than older Python versions when running the same piece of code.
Conclusion
We have concluded that Python 3.11 is faster. The question you may ask is, why is it faster?
Here are some improvements that have been made in Python 3.11:
-
Improved memory management: Python 3.11 includes several improvements to the memory allocator, which can result in faster memory allocation and better overall performance.
-
Improved support for concurrent execution: Python 3.11 includes a new concurrent execution model called "Parallel Execution" that allows multiple threads to be executed concurrently on multiple processors or cores. This can lead to faster execution of concurrent tasks.
-
Optimizations to the interpreter: The Python interpreter has been optimized in Python 3.11 to improve the performance of common operations, such as dictionary lookups and attribute access.
I think that just moving to the latest Python version for most software will improve performance without the need for doing anything special, which is pretty amazing. I was listening to Lex Fridman's podcast show where he interviewed Guido van Rossum. Some of the discussion topics included Python 3.11.
I recommend checking out the show here
About the Author
Aleksandro Matejic, a Cloud Architect, began working in the IT industry over 21 years ago as a technical specialist, right after his studies. Since then, he has worked in various companies and industries in various system engineer and IT architect roles. He currently works on designing Cloud solutions, Kubernetes, and other DevOps technologies.
In his spare time, Aleksandro works on different development projects such as developing devoriales.com, a blog and learning platform launching in 2022/2023. In addition, he likes to read and write technical articles about software development and DevOps methods and tools. You can contact Aleksandro by visiting his LinkedIn Profile.