Numba
Table of Contents
from numba import jit
#from numpy.random import random
from random import random

import timeit

def monte_carlo_pi(nsamples):# Function is compiled and runs in machine code
    acc = 0
    for i in range(nsamples):
        x = random()
        y = random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

@jit(nopython=True)
def monte_carlo_pi_numba(nsamples):# Function is compiled and runs in machine code
    acc = 0
    for i in range(nsamples):
        x = random()
        y = random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

t = timeit.timeit("monte_carlo_pi_numba(1000000)", setup="from __main__ import monte_carlo_pi_numba", number=100)
print('Running time of {:30s} : {:.2f}s'.format('monte_carlo_pi_numba(1000000)', t))

t = timeit.timeit("monte_carlo_pi_cython(1000000)", setup="from _mc_cython import monte_carlo_pi_cython", number=100)
print('Running time of {:30s} : {:.2f}s'.format('monte_carlo_pi_cython(1000000)', t))

t = timeit.timeit("monte_carlo_pi(1000000)", setup="from __main__ import monte_carlo_pi", number=100)
print('Running time of {:30s} : {:.2f}s'.format('monte_carlo_pi(1000000)', t))

'''
Call 100 Monte Carlo runs, each run samples 1000000 points

random.random()
Running time of monte_carlo_pi_numba(1000000)  : 1.67s
Running time of monte_carlo_pi_cython(1000000) : 4.21s
Running time of monte_carlo_pi(1000000)        : 34.29s

numpy.random.random()
Running time of monte_carlo_pi_numba(1000000)  : 1.75s
Running time of monte_carlo_pi_cython(1000000) : 52.38s
Running time of monte_carlo_pi(1000000)        : 84.34s
'''