<p>Python typically runs all your code on a single core. Even when the program that you're running has components that can easily run in parallel. To make programs faster in parallel scenarios you might want to explore <a href="https://github.com/ray-project/ray">ray</a>. It's not the only tool for this use-case but it's a tool we've come to like.</p>

1 - Introduction
2 - Speed
3 - Rerun
4 - Overhead
5 - Performance

The base simulation will run with the code below.

import numpy as np

def birthday_experiment(class_size, n_sim=1000):
    """Simulates the birthday paradox. Vectorized = Fast!"""
    sims = np.random.randint(1, 365 + 1, (n_sim, class_size))
    sort_sims = np.sort(sims, axis=1)
    n_uniq = (sort_sims[:, 1:] != sort_sims[:, :-1]).sum(axis = 1) + 1
    return {"est_prob": np.mean(n_uniq != class_size)}

You can time how long this takes.

results = [birthday_experiment(class_size=size, n_sim=10_000) for size in range(2, 100)]

Note that the %%time command is a noisy measurement.