Slide 1: Introduction to Cython
Cython is a powerful tool for optimizing Python code by converting it to C, resulting in significant performance improvements. It allows developers to write Python-like code that compiles to efficient C extensions, bridging the gap between Python's ease of use and C's speed.
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Usage
result = fibonacci(10)
print(f"The 10th Fibonacci number is: {result}")Slide 2: Setting Up Cython
To use Cython, you need to install it and set up your development environment. This slide demonstrates how to install Cython using pip and create a basic Cython file.
!pip install cython
# Create a Cython file (example.pyx)
%%writefile example.pyx
def greet(name):
return f"Hello, {name}!"
# Create a setup.py file
%%writefile setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("example.pyx")
)
# Compile the Cython code
!python setup.py build_ext --inplaceSlide 3: Static Typing in Cython
One of Cython's key features is static typing, which can significantly improve performance. This slide shows how to use static typing in Cython.
def calculate_sum(int a, int b):
cdef int result = a + b
return result
# Usage in Python
import example
result = example.calculate_sum(5, 7)
print(f"The sum is: {result}")Slide 4: Using C Data Types
Cython allows the use of C data types for even better performance. This slide demonstrates how to declare and use C data types in Cython.
cdef extern from "math.h":
double sqrt(double x)
def calculate_hypotenuse(double a, double b):
cdef double c_squared = a * a + b * b
return sqrt(c_squared)
# Usage in Python
import example
hypotenuse = example.calculate_hypotenuse(3.0, 4.0)
print(f"The hypotenuse is: {hypotenuse}")Slide 5: Numpy Integration
Cython works seamlessly with Numpy, allowing for high-performance numerical computations. This slide shows how to use Cython with Numpy arrays.
import numpy as np
cimport numpy as np
def vector_add(np.ndarray[double, ndim=1] a, np.ndarray[double, ndim=1] b):
cdef int i
cdef int n = a.shape[0]
cdef np.ndarray[double, ndim=1] result = np.zeros(n, dtype=np.double)
for i in range(n):
result[i] = a[i] + b[i]
return result
# Usage in Python
import numpy as np
import example
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])
result = example.vector_add(a, b)
print(f"The result of vector addition: {result}")Slide 6: Parallelization with OpenMP
Cython supports OpenMP, enabling easy parallelization of code. This slide demonstrates how to use OpenMP in Cython for parallel processing.
cimport cython
from cython.parallel import prange
@cython.boundscheck(False)
@cython.wraparound(False)
def parallel_sum(double[:] arr):
cdef int i
cdef double total = 0.0
cdef int n = arr.shape[0]
for i in prange(n, nogil=True):
total += arr[i]
return total
# Usage in Python
import numpy as np
import example
arr = np.random.rand(1000000)
result = example.parallel_sum(arr)
print(f"The sum of the array is: {result}")Slide 7: Profiling Cython Code
Profiling is crucial for identifying performance bottlenecks. This slide shows how to profile Cython code using the cProfile module.
import example # Assuming this is your compiled Cython module
def test_function():
for _ in range(1000000):
example.some_cython_function()
cProfile.run('test_function()')Slide 8: Memory Views
Memory views in Cython provide a powerful way to work with contiguous memory buffers. This slide demonstrates how to use memory views for efficient array operations.
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def scale_array(double[:] arr, double factor):
cdef int i
cdef int n = arr.shape[0]
for i in range(n):
arr[i] *= factor
# Usage in Python
import numpy as np
import example
arr = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
example.scale_array(arr, 2.0)
print(f"Scaled array: {arr}")Slide 9: Extension Types
Extension types in Cython allow you to create efficient Python classes with C-level attributes and methods. This slide shows how to define and use extension types.
cdef class Point:
cdef public double x, y
def __init__(self, double x, double y):
self.x = x
self.y = y
cpdef double distance(self, Point other):
cdef double dx = self.x - other.x
cdef double dy = self.y - other.y
return (dx * dx + dy * dy) ** 0.5
# Usage in Python
import example
p1 = example.Point(0.0, 0.0)
p2 = example.Point(3.0, 4.0)
distance = p1.distance(p2)
print(f"The distance between the points is: {distance}")Slide 10: Wrapping C Libraries
Cython excels at wrapping C libraries for use in Python. This slide demonstrates how to wrap a simple C function using Cython.
cdef extern from "math.h":
double cos(double x)
def py_cos(double x):
return cos(x)
# Usage in Python
import example
import math
angle = math.pi / 3
result = example.py_cos(angle)
print(f"The cosine of pi/3 is: {result}")Slide 11: Real-Life Example: Image Processing
This slide presents a real-life example of using Cython to optimize image processing operations, demonstrating significant performance improvements over pure Python.
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def apply_threshold(np.ndarray[np.uint8_t, ndim=2] image, int threshold):
cdef int height = image.shape[0]
cdef int width = image.shape[1]
cdef np.ndarray[np.uint8_t, ndim=2] result = np.zeros((height, width), dtype=np.uint8)
cdef int i, j
for i in range(height):
for j in range(width):
if image[i, j] > threshold:
result[i, j] = 255
else:
result[i, j] = 0
return result
# Usage in Python
import numpy as np
from PIL import Image
import image_processing
# Load an image
image = np.array(Image.open("example_image.jpg").convert("L"))
# Apply threshold
result = image_processing.apply_threshold(image, 128)
# Save the result
Image.fromarray(result).save("thresholded_image.jpg")Slide 12: Real-Life Example: Monte Carlo Simulation
This slide showcases another real-life example, demonstrating how Cython can be used to speed up Monte Carlo simulations for estimating pi.
import numpy as np
cimport numpy as np
cimport cython
from libc.math cimport sqrt
@cython.boundscheck(False)
@cython.wraparound(False)
def estimate_pi(int n):
cdef int inside = 0
cdef double x, y
cdef int i
for i in range(n):
x = np.random.uniform(-1, 1)
y = np.random.uniform(-1, 1)
if sqrt(x*x + y*y) <= 1:
inside += 1
return 4 * inside / n
# Usage in Python
import monte_carlo
import time
start_time = time.time()
estimated_pi = monte_carlo.estimate_pi(1000000)
end_time = time.time()
print(f"Estimated pi: {estimated_pi}")
print(f"Time taken: {end_time - start_time:.2f} seconds")Slide 13: Best Practices and Tips
When using Cython, follow these best practices for optimal performance:
- Use static typing wherever possible
- Minimize Python object creation within tight loops
- Use memory views for efficient array operations
- Profile your code to identify bottlenecks
- Leverage compiler directives like @cython.boundscheck(False) judiciously
- Utilize parallel processing with OpenMP for computationally intensive tasks
- Wrap existing C libraries instead of reimplementing them
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def optimized_function(double[:] arr):
cdef int i
cdef double result = 0.0
for i in range(arr.shape[0]):
result += arr[i]
return resultSlide 14: Additional Resources
For further exploration of Cython and its capabilities, consider the following resources:
- Cython Documentation: https://cython.readthedocs.io/
- "Cython: A Guide for Python Programmers" by Kurt W. Smith
- ArXiv paper: "Cython: The Best of Both Worlds" (https://arxiv.org/abs/1102.1523)
- Cython GitHub repository: https://github.com/cython/cython
- Scipy Lecture Notes on Cython: https://scipy-lectures.org/advanced/optimizing/