liveBook · Manning

Cython

As explained in Fast Python: High performance techniques for large datasets

Cython is a Python-derived programming language and compiler that supports static typing and translates annotated code into C or C++ extension code.

Cython is a Python superset that compiles to C. It is useful when a measured bottleneck needs custom, faster code that still works with Python and NumPy. Compilation alone is not the optimization: the expensive path must avoid Python-object operations. section 5.0 section 5.8

Start with an image filter

A baseline filter converts each RGB pixel to grayscale, then darkens it using a second image. Python code loads the images and imports a .pyx module through pyximport, which compiles and links it. The first Cython implementation still uses NumPy operations inside nested pixel loops; it establishes a comparison, not a guaranteed speedup. Exclude import-time compilation when measuring the filter. section 5.2 section 5.2.1

Optimize the measured hot path in stages:

  • Declare argument and local types. An annotated integer addition becomes native C arithmetic in the generated implementation, although calls from Python still cross a wrapper. Use def for a Python interface, cdef for Cython-only calls, or cpdef for both; keep intensive work behind the Python-facing boundary. section 5.2.3 section 5.2.4
  • Profile again rather than guessing. Enable linetrace and compile with CYTHON_TRACE for line_profiler; its instrumentation changes absolute timings. Use cython -a to locate remaining interactions with Python. section 5.3.2 section 5.4
  • Convert NumPy arrays to typed memoryviews at the boundary, then pass views into the inner function. Memoryviews expose array data, shape, and strides without making each access a Python-object operation; continue profiling, because other interactions can remain. section 5.4 section 5.4.1
  • Choose an execution pattern that fits the algorithm. A Cython NumPy generalized universal function handles pixel-by-pixel work and gains broadcasting, but does not suffice when a result needs other array positions. For threaded loops, first remove GIL-dependent calls, then use nogil and Cython’s OpenMP-based prange. section 5.5 section 5.5.1 section 5.7
#cython: language_level=3
 
def add4(my_number):
    i = my_number + 4
    return i
 
def add4_annotated(int my_number):
    cdef int i
    i = my_number + 4
    return i

Compare the untyped and annotated add4 functions before inspecting their generated C: the small declaration changes what happens inside the implementation. section 5.2.3

When pixels depend on neighbors

A color Game of Life needs neighboring cells, so its core uses typed array views rather than an elementwise universal function. An extended board copies opposite edges into a border, avoiding boundary tests in the inner loop at a memory cost. For a 1,000 × 1,000 board over 200 generations, the reported Python run took just under 1,000 seconds versus 2.5 seconds for Cython. Larger, differently shaped boards also produced markedly different timings despite equal cell counts: benchmark the actual layout and workload. section 5.6 section 5.6.1 section 5.6.2

Cython is one option, not an automatic winner over existing libraries or Numba. With pandas, the route is through its NumPy arrays, not a direct Cython–pandas interface; measure competing approaches for the data and hardware at hand. section 5.1 section 7.3.3

How Fast Python: High performance techniques for large datasets covers it

How deep it goes
Works through typing, generated C, profiling, memoryviews, universal functions, and GIL-free loops; defers compilation details and general parallel-programming techniques.
Examples
Uses an RGB image-darkening filter, typed integer addition, a color Game of Life, and fare-tip analysis.
What it assumes
Assumes working Python and NumPy knowledge, but introduces Cython through a small project without requiring proficiency in C.
What you can do after
Build it from scratch: profile and refactor a NumPy-backed computation into typed Cython code, then assess whether GIL-free threading fits.
How it connects
Connects NumPy memoryviews, generalized universal functions, Python wrappers, the GIL, OpenMP, and pandas array extraction.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Fast Python: High performance techniques for large datasets. The section links point to the parts of the book it draws on.