What problems fit Cython and Dask?

Objectives

  • Recognize workloads suited to Cython, Dask, both tools, or neither.

  • Identify granularity, data-sharing, and maintenance constraints before implementation.

  • Form a testable optimization hypothesis.

Instructor note

  • 15 min teaching

  • 10 min exercise

Start from the expensive work

Do not select a tool from the project name or data size alone. Ask what executes inside the expensive region, whether calls are independent, how much data must move, and how long one useful unit of work lasts.

Evidence

Strong first candidate

Why

A specialized Python numerical loop dominates

Cython

Native types and operations can remove interpreter overhead

Many independent CPU-heavy Python functions

Dask processes

Separate interpreters bypass the single-process GIL

Many independent native kernels release the GIL

Dask threads

Threads share memory and can execute the native work concurrently

One costly kernel is called for many independent inputs

Cython, then Dask

Optimize work within each call, then schedule calls across cores

An existing NumPy/SciPy operation already implements the work

Existing library first

It is usually simpler and already compiled and tested

Tiny functions or tightly coupled shared updates

Neither initially

Scheduling or synchronization may exceed useful work

Cython fit

Cython is a good candidate when the hot region is stable, loop-heavy, numerically typed, and difficult to express with an existing optimized array operation. It is less attractive for code dominated by I/O, rapidly changing orchestration, or Python objects whose dynamic behavior must remain inside every iteration.

The maintenance cost includes a native compiler, platform-specific build products, more specialized source, and additional correctness risks from C numeric and memory semantics.

Dask fit

Dask is a good candidate when work can be expressed as a graph of tasks or operations on chunked arrays/tables. Tasks should contain enough work to amortize scheduling, and transferred inputs/results should fit the node’s memory and bandwidth budget.

Dask cannot turn a sequential dependency chain into parallel work, and it does not remove Python interpreter overhead inside each task.

Decision flow from measured bottleneck to existing libraries, Cython, Dask processes, Dask threads, or restructuring.

The decision flow is a starting hypothesis, not a substitute for measurement. A workload can move through more than one branch—for example, Cython can accelerate a kernel before Dask schedules independent calls to it.

Form a hypothesis

Write the intended cause and observable result before implementation:

The integration loop spends most of its time executing Python numeric operations. Typing it and calling C math through Cython should reduce time while preserving the result within tolerance.

Eight integrations are independent. Once the compiled loop releases the GIL, Dask threads should execute them concurrently without process serialization.

These hypotheses can be disproved, which makes them useful.

Exercise

For each workload, choose Cython, Dask threads, Dask processes, both tools, an existing library, or “measure/restructure first.” State one reason and one measurement.

  1. A pandas operation on a 20 MB table takes 50 ms.

  2. A nested Python loop computes a custom recurrence for 30 seconds.

  3. One hundred independent calls to that recurrence use different parameters.

  4. A NumPy matrix multiplication is slow when four Dask processes run it simultaneously.

  5. Every task updates the same shared Python dictionary.

Keypoints

  • Tool selection follows execution evidence, independence, granularity, and data movement.

  • Cython changes work inside a kernel; Dask schedules tasks or chunks.

  • Existing optimized libraries and algorithmic changes remain the preferred simpler solutions when they fit.

See also

Apply the decision to a native kernel in Cython concepts and practice, and keep the selection guide nearby.