High-performance Python – compiled code and C interface

Step Lively

Cython Examples

Cython can accept almost any valid Python source file to produce C code. Compiling the C code is fairly simple. The first step in using Cython is the easiest: Select the code you want and put it into a separate file. You can have more than one function per file if you like.

The second step is to create the setup.py file, which is like a makefile for Python. It defines what Python file you want to compile into a shareable library and is where you can put options (e.g., compile options) you want to use. After compiling, be sure to test the code.

Here, I use two examples from a Cython tutorial [13]. The first is a simple Hello World example, and the second is a summation example that uses a loop.

Hello World

The Python code to be compiled in the helloworld.pyx file is

print("Hello World")

which is just about the simplest one-line Python script you can have. As previously mentioned, you need to create a setup.py file that is really a Python makefile:

from distutils.core import setup
from Cython.Build import cythonize
setup(
  ext_modules=cythonize("helloworld.pyx")
)

The first two lines are fairly standard for a Python setup.py file. After that, the setup command builds the binary (shared object). In this case, the command is to cythonize the helloworld.pyx file. To make life easier, be sure to put this file in the same directory as the code.

The system I used had Ubuntu 18.04 (with updates) and the Anaconda Python distribution. To build the binary, enter

$ python3 setup.py build_ext --inplace

The output is shown in Listing 3. Note that the command line uses setup.py as the "configuration" for building the binary (shared object). In the output, you will see paths that correspond to the system I used. Don't worry about this because setup.py takes care of the paths.

Listing 3

Binary Build

$ python3 setup.py build_ext --inplace
Compiling helloworld.py because it changed.
[1/1] Cythonizing helloworld.pyx
/home/laytonjb/anaconda3/lib/python3.7/site-packages/Cython/Compiler/Main.py:367: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /home/laytonjb/HPC-PYTHON-1/helloworld.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)
running build_ext
building 'helloworld' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -B /home/laytonjb/anaconda3/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/laytonjb/anaconda3/include/python3.7m -c helloworld.c -o build/temp.linux-x86_64-3.7/helloworld.o
gcc -pthread -shared -B /home/laytonjb/anaconda3/compiler_compat -L/home/laytonjb/anaconda3/lib -Wl,-rpath=/home/laytonjb/anaconda3/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.7/helloworld.o -o /home/laytonjb/HPC-PYTHON-1/helloworld.cpython-37m-x86_64-linux-gnu.so

Now I can test the compiled Cython shared object:

>>> import helloworld
Hello World

It worked! These are the basic steps for creating a compiled binary (shared object) of Python code.

Summing

To begin, I'll take some simple Python code from the Numba example and compute the sum of a one-dimensional list. Although I'm sure better code is out there for computing a sum, this example will teach you how to do a more mathematical example.

For this example, a simple function in the sum.pyx file computes the sum:

def sum(x):
   total = 0
   for i in range(x.shape[0]):
      total += x[i]
   return total

The code is compiled the same way as the Hello World code, with a change to the Python function in setup.py to cythonize sum.pyx. The code in Listing 4 tests the module in a Jupyter notebook.

Listing 4

Summation Test

import sum
import numpy
x = numpy.arange(10_000_000);
%time sum.sum(x)
CPU times: user 1.37 s, sys: 0 ns, total: 1.37 s
Wall time: 1.37 s

Notice that sum is the object and sum.sum is the function within the object, which means you can put more than one function in your Python code. Also notice that the time for running the code is about the same as the pure Python itself. Although you can optimize Cython code by, for example, employing OpenMP, I won't discuss that here.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs



Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>
	</a>

<hr>		    
			</div>
		    		</div>

		<div class=