Make a large set of random integers
In [ ]:
from array import array
from random import randint
a = array('i', (randint(-1000, 1000) for _ in range(10000000)))
Simple way to sum with a for loop
In [ ]:
def sum_py(a):
s = 0
for x in a: s += x
return s
Time the baseline simple sum methods
In [ ]:
%timeit sum_py(a)
%timeit sum(a)
Compile with Cython
In [ ]:
# needs to be run once every time the kernel is started
%load_ext cython
In [ ]:
%%cython
def sum_cy(a):
s = 0
for x in a: s += x
return s
In [ ]:
%timeit sum(a)
%timeit sum_cy(a)
Static Typing
In [ ]:
%%cython
def sum_cy_st(a):
cdef int x, s = 0
for x in a: s += x
return s
In [ ]:
%timeit sum(a)
%timeit sum_cy_st(a)
Colorized Annotations
In [ ]:
%%cython --annotate
def sum_cy_st(a):
cdef int x, s = 0
for x in a:
s += x
return s
Typed Memoryviews
In [ ]:
%%cython --annotate
from cpython cimport array
def sum_cy_tm(int[:] a):
cdef int x, s = 0
for x in a:
s += x
return s
In [ ]:
%timeit sum(a)
%timeit sum_cy_tm(a)
With C-like looping
In [12]:
%%cython --annotate
from cpython cimport array
def sum_cy_tm(int[:] a):
cdef int i, n = a.shape[0], s = 0
for i in range(n):
s += a[i]
return s
Out[12]:
In [13]:
%timeit sum(a)
%timeit sum_cy_tm(a)
Compile Optimizations
In [14]:
%%cython --annotate
cimport cython
from cpython cimport array
@cython.boundscheck(False)
@cython.wraparound(False)
def sum_cy_co(int[:] a):
cdef int i, n = a.shape[0], s = 0
for i in range(n):
s += a[i]
return s
Out[14]:
In [15]:
%timeit sum(a)
%timeit sum_cy_co(a)
Memoryview Layout
In [16]:
%%cython --annotate
cimport cython
from cpython cimport array
@cython.boundscheck(False)
@cython.wraparound(False)
def sum_cy_cc(int[::1] a):
cdef int i, n = a.shape[0], s = 0
for i in range(n):
s += a[i]
return s
Out[16]:
In [17]:
%timeit sum(a)
%timeit sum_cy_cc(a)
Multithreading
In [18]:
%%cython
cimport cython
from cpython cimport array
@cython.boundscheck(False)
@cython.wraparound(False)
def __sum_gil(int[::1] a, int[:] out):
cdef int i, n = a.shape[0], s = 0
for i in range(n): s += a[i]
out[0] = s
def sum_par(int[::1] a):
cdef int[::1] A1 = a[0 : a.shape[0]//2]
cdef int[::1] A2 = a[a.shape[0]//2 : a.shape[0]]
cdef int[:] out = array.array('i', (0,0))
from threading import Thread
T1 = Thread(target=__sum_gil, args=(A1, out[0:1]))
T2 = Thread(target=__sum_gil, args=(A2, out[1:2]))
T1.start(); T2.start()
T1.join(); T2.join()
return out[0] + out[1]
In [19]:
%timeit sum(a)
%timeit sum_par(a)
With release of the GIL
In [20]:
%%cython
cimport cython
from cpython cimport array
@cython.boundscheck(False)
@cython.wraparound(False)
def __sum_gil(int[::1] a, int[:] out):
cdef int i, n = a.shape[0], s = 0
with nogil:
for i in range(n): s += a[i]
out[0] = s
def sum_par(int[::1] a):
cdef int[::1] A1 = a[0 : a.shape[0]//2]
cdef int[::1] A2 = a[a.shape[0]//2 : a.shape[0]]
cdef int[:] out = array.array('i', (0,0))
from threading import Thread
T1 = Thread(target=__sum_gil, args=(A1, out[0:1]))
T2 = Thread(target=__sum_gil, args=(A2, out[1:2]))
T1.start(); T2.start()
T1.join(); T2.join()
return out[0] + out[1]
In [21]:
%timeit sum(a)
%timeit sum_par(a)
Interfacing with C Code
Need sum.h with int sum_c(int* a, int n); and sum.c with the following:
#include "sum.h"
int sum_c(int* a, int n) {
int i, s = 0;
for (i = 0; i < n; ++i) { s += a[i]; }
return s;
}
Also, the following needs to be updated where -I is the path to where the above is saved.
In [22]:
%%cython -I C:/Python27/notebooks
#distutils: sources=sum.c
cimport cython
from cpython cimport array
cdef extern from "sum.h" nogil:
cdef int sum_c(int* a, int n)
@cython.boundscheck(False)
@cython.wraparound(False)
def sum_cy_c(int[::1] a):
cdef int out
with nogil: out = sum_c(&a[0], a.shape[0])
return out
In [23]:
%timeit sum_cy_cc(a)
%timeit sum_cy_c(a)
Numpy Equivilent
In [24]:
import numpy as np
#np_a = np.random.randint(-1000, 1000, size=10000000)
np_a = np.array(a)
%timeit sum(np_a)
%timeit np_a.sum()
%timeit sum_cy_cc(a)
Check they all sum properly
In [25]:
(sum_py(a), sum_cy(a), sum(a), sum_cy_st(a), sum_cy_tm(a), sum_cy_co(a),
sum_cy_cc(a), sum_par(a), sum_cy_c(a), np_a.sum())
Out[25]:
In [ ]: