Faster Python code with Numba

Linnart Felkl M.Sc. ETH
2 min readNov 2, 2022

--

I develop simulation models in Python. An essential part of simulation modeling is simulation runtime. Large discrete-event simulation models and even medium-sized agent-based simulation models consume computational ressources and can have a very long runtime. This is especially true if the source code is fully written in Python. I therefore conducted some tests with Numba in Python. I share my results here. I run a simple test on a test function in Python.

Installing Numba in Python

Numba can be installed using the pip install command. Simply type the following into your terminal:

pip install numba

For lists I recommend that you use numpy (i.e. numpy arrays), as this will allow you to avoid default Python list. If not already installed you can install numpy in the same way.

You can now import numpy and numba and use numba to make your code run faster. For this you can use the @njit decorator.

Testing Numba performance improvement in Python

Time to have a look at a simple runtime improvement test in Python. Below code implements Numba to have a faster Python program.

import numpy as np 
from numba import jit
import random
import time
def rand_events(n: int) -> np.ndarray:
ls = np.zeros(n)
for i in range(n):
x = random.random()
while True:
y = random.random()
if x < y:
ls[i] = y
break
return ls
""" RUNTIME TEST WITHOUT NUMBA -------------------------- """ _start_time = time.time()
vals = rand_events(10000000)
_end_time = time.time()
print(str(_end_time - _start_time))
""" RUNTIME TEST WITH NUMBA ------------------------------ """
_start_time = time.time()
jit_rand_events = jit(nopython=True)(rand_events)
vals = jit_rand_events(10000000)
_end_time = time.time()
print(str(_end_time-_start_time))
_start_time = time.time()
vals = jit_rand_events(10000000)
_end_time = time.time()
print(str(_end_time-_start_time))

In above code calling jit(nopython=True) equals the use of the @njit declarator. When running above code the output in the terminal will be something similar to the following (depends on machine and random number generation outcome)

9.1829195022583 
1.2913379669189453
0.8751001358032227

This means that it took 9.18 sec to call the rand_events() function with n = 10,000,000. After applying the @njit declarator and running the function again, it takes only 1.29 sec (including “jitting” the function). Without the call of the @njit declarator it would take 0.87 sec to call the “jitted” version of rand_events(). That is a significant runtime improvement.

Applying Numba for faster Python simulations

Numba can make simulation frameworks faster. But only if major parts of the framework are numerically oriented. In addition, the framework should integrate numpy, as numba understands numpy very well. In a strongly object oriented framework this can be a challenge. But if you can manage to transform computationally intensive parts of the code into numerical code then numba can result in significant runtime improvements of Python code.

Originally published at https://www.supplychaindataanalytics.com on November 2, 2022.

--

--