00 Cython nedir, neden
Python yavaş — ama tam olarak nerede ve ne kadar? Cython bu sorunun cerrahi cevabı.
CPython, her Python satırını bytecode'a derler ve bu bytecode'u yorumlayan bir C döngüsünde çalıştırır. Her nesne bir PyObject* işaretçisidir; her değişken erişimi referans sayacı günceller; her aritmetik işlem tip denetimi yapan bir C fonksiyonu çağırır. Bu esnekliğin bedeli hızdır.
Cython bu denklemi tersine çevirir: .pyx uzantılı dosyalarda Python sözdiziminin üstüne C tip bildirimleri eklenir. Cython derleyicisi bu dosyayı C koduna çevirir; C kodu daha sonra normal bir C derleyicisi ile derlenerek bir CPython uzantı modülü (.so / .pyd) üretilir. Sonuç Python'dan import edilir, ama içeride saf C çalışır.
1 hello.pyx ← Python + C tip bildirimleri │ ▼ cython 2 hello.c ← ~2000 satır üretilmiş C kodu │ ▼ gcc / clang 3 hello.cpython-311-x86_64-linux-gnu.so │ ▼ import hello 4 Python içinde C hızında çalışan modül
Kademeli dönüştürme
Cython'un en güçlü özelliği: bir .py dosyasını doğrudan .pyx olarak derleyebilirsiniz. Hiçbir tip eklemeden bile küçük bir hız kazancı gelir. Sonra sadece dar boğaz olan fonksiyonlara tip bildirimi eklenirse kazanç dramatikleşir. Tüm projeyi yeniden yazmak gerekmez.
Alternatifler tablosu
| Cython | .pyx → C → .so, AOT derleme. Kademeli dönüştürme, C API'ye tam erişim. Build pipeline karmaşık. |
| numba | @jit ile runtime LLVM derlemesi. Kurulum gerekmez, sadece dekoratör. NumPy odaklı, genel Python nesnelerine zayıf. |
| ctypes | Stdlib FFI; mevcut .so/.dll'i runtime'da çağırır. Derleme gerekmez, ama yavaş ve manuel tip yönetimi yorucu. |
| cffi | ctypes'tan temiz API. PyPy dostu. AOT veya ABI modu. Cython kadar performans kazanmaz. |
| pybind11 | C++ kütüphanelerini Python'a bağlamak için. Header-only, modern C++11. C++ yazmak zorundasın. |
| PyO3 | Rust → Python bağlaması. Cargo ile derle, Rust güvenliği elde et. Rust öğrenmek gerekiyor. |
| nanobind | pybind11'in halefi; daha hızlı derleme, daha küçük binary. Henüz genç, API değişiyor. |
Ne zaman Cython, ne zaman değil
- Saf Python döngüsü dar boğaz — NumPy vektorizasyonu uygulanamıyor
- Mevcut bir C kütüphanesini Python'a sarmak istiyorsun
- NumPy işlem sonrası element-wise hesaplama gerekliyse
- GIL release ederek gerçek paralel CPU kullanmak istiyorsan
- Mevcut Python kodunu adım adım, modül modül hızlandırmak istiyorsun
- Zaten NumPy vektorizasyonu kullanıyorsun — ekstra kazanç marjinal
- I/O darboğazı var — disk veya ağ bekliyorsa CPU optimizasyonu fark etmez
- Küçük script, kısa ömürlü — build pipeline getirisi negatif
- Cross-compile derdi yok — wheel oluşturmak her platform için ayrı CI gerektirir
01 Kurulum ve ilk derleme ortamı
Cython kendi başına derleme yapmaz — bir C derleyicisine ve Python geliştirici başlıklarına ihtiyaç duyar.
Sistem gereksinimleri
| Linux | sudo apt install gcc python3-dev python3-venv (Debian/Ubuntu) |
| macOS | xcode-select --install — Clang + Python başlıkları birlikte gelir |
| Windows | Visual Studio Build Tools gerekli: C++ build tools workload seçili olmalı. Python sürümüyle eşleşen MSVC versiyonu. |
Sanal ortam oluştur ve aktif et
mkdir cython-demo && cd cython-demo
python3 -m venv .venv
source .venv/bin/activate
Windows: .venv\Scripts\activate
Cython'u kur
pip install cython setuptools
cython --version # Cython version 3.x.x
.pyx dosyasını C koduna çevirirsetup.py ve pyproject.toml desteğiHızlı doğrulama
python -c "import Cython; print(Cython.__version__)"
# 3.0.11 (ya da benzer)
python -c "import sysconfig; print(sysconfig.get_config_var('CC'))"
# gcc — derleyici bulundu
Cython'un ürettiği C kodu Python.h başlık dosyasını include eder. Bu dosya Python yorumlayıcısının C API'sidir; runtime paketinde değil, geliştirici paketinde (python3-dev / python3-devel) bulunur.
02 İlk .pyx dosyası ve setup.py derlemesi
Sıfırdan çalışan bir uzantı modülü — üç dosya, tek komut.
hello.pyx
def greet(name):
return f"Merhaba, {name}!"
def square(x):
return x * x
Şu an bu dosya tamamen geçerli Python — Cython'a özgü hiçbir şey yok. Bunu bile derleyebiliriz.
setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("hello.pyx", language_level=3)
)
.pyx dosyasından Extension nesnesi üretir; Cython derleyicisini çağırırDerleme
python setup.py build_ext --inplace
# Running build_ext
# building 'hello' extension
# gcc -shared -fPIC ... -o hello.cpython-311-x86_64-linux-gnu.so
Bu komut iki şey üretir:
| hello.c | Cython'un ürettiği C kodu (~1800–2500 satır). Silme — yeniden build gerekirse yeniden üretilir |
| hello.cpython-311-x86_64-linux-gnu.so | Derlenmiş uzantı modülü. Platform ve Python sürümüne özgü |
Import et ve çalıştır
python -c "import hello; print(hello.greet('Ali')); print(hello.square(7))"
Merhaba, Ali!
49
Geliştirme modu: pyximport
Her değişiklikte setup.py çalıştırmak yerine pyximport kullanılabilir — import anında otomatik derler:
import pyximport
pyximport.install(language_level=3)
import hello # ilk kullanımda derlenir
print(hello.greet('Ali'))
pyximport sadece geliştirme için — C başlıkları, özel flag'ler veya ek C kaynakları gerektiren modüller için çalışmaz. Production build'lerde her zaman setup.py veya pyproject.toml kullanın.
Üretilen C koduna bakmak
wc -l hello.c
2156 hello.c
head -30 hello.c
# /* Generated by Cython 3.x.x */
# #define PY_SSIZE_T_CLEAN
# #include "Python.h"
# ...
Bu kodu okumak zorunda değilsiniz — ama "ne üretildi" merakı için açmak normaldir. Bölüm 09'da annotation HTML daha insancıl bir alternatif sunacak.
03 Statik tipler: def / cdef / cpdef
Cython'un performans kazancının büyük kısmı tip bildirimlerinden gelir — Python'un runtime tip sorgusu ortadan kalkar.
Üç fonksiyon çeşidi
def |
Normal Python fonksiyonu. Python tarafından çağrılabilir. Her argüman PyObject* geçişi yapar. En yavaş. |
cdef |
Saf C fonksiyonu. Sadece Cython veya C kodundan çağrılabilir — Python'dan erişilemez. En hızlı. |
cpdef |
İkili sürüm. Python'dan çağrıldığında def gibi, Cython içinden çağrıldığında cdef gibi davranır. |
# Versiyon A — saf Python (tip yok)
def fib_py(n):
a, b = 0, 1
while b < n:
a, b = b, a + b
return b
# Versiyon B — def + cdef lokal değişkenler
def fib_typed(long n):
cdef long a = 0, b = 1
while b < n:
a, b = b, a + b
return b
# Versiyon C — saf C fonksiyonu (Python'dan çağrılamaz)
cdef long _fib_c(long n):
cdef long a = 0, b = 1
while b < n:
a, b = b, a + b
return b
# Python wrapper — cdef fonksiyonunu dışarıya açar
cpdef long fib(long n):
return _fib_c(n)
Yaygın C tipleri
int32_t kullanın)float32 dizileriyle uyumluint olarak saklanır, Python bool olarak dönermalloc/memcpy argümanları için standartFibonacci benchmark
python -m timeit -s "import fib" "fib.fib_py(1_000_000)"
1000000 loops, best of 5: 4.12 µs per loop
python -m timeit -s "import fib" "fib.fib_typed(1_000_000)"
1000000 loops, best of 5: 0.31 µs per loop
python -m timeit -s "import fib" "fib.fib(1_000_000)"
1000000 loops, best of 5: 0.09 µs per loop
Saf Python → tipli def → saf cdef: yaklaşık 13×, ardından ek 3× daha. Fibonacci küçük bir örnektir; döngü sayısı arttıkça fark büyür.
Public API için cpdef; sadece iç hesaplama için cdef; Python nesneleri alan/döndüren arayüz için def. İç döngü ne kadar saf C olursa performans o kadar artar.
04 C tipleri, struct, ctypedef, pointer
Cython, C'nin tip sistemine doğrudan erişim verir — struct, union, pointer ve bellek yönetimi.
struct ve ctypedef
cdef struct Point:
double x
double y
ctypedef double real_t # tip takma adı
cdef union IntOrFloat:
int i
float f
cpdef double distance(Point a, Point b):
cdef double dx = a.x - b.x
cdef double dy = a.y - b.y
from libc.math cimport sqrt
return sqrt(dx*dx + dy*dy)
def test_distance():
cdef Point p1 = Point(x=0.0, y=0.0)
cdef Point p2 = Point(x=3.0, y=4.0)
return distance(p1, p2) # → 5.0
Pointer ve manuel bellek yönetimi
from libc.stdlib cimport malloc, free
from libc.string cimport memset
def make_array(int n):
cdef int* arr
cdef int i
arr = <int*>malloc(n * sizeof(int))
if arr == NULL:
raise MemoryError("malloc başarısız")
for i in range(n):
arr[i] = i * i # pointer aritmetiği: arr[i] = *(arr + i)
result = [arr[i] for i in range(n)]
free(arr) # MUTLAKA serbest bırak
return result
(int*) ifadesine denk gelirsizeof operatörü — tip veya değişken alırmalloc başarısız olursa dönermalloc için bir free — yoksa bellek sızıntısı olurHazır libc cimport'ları
from libc.stdlib cimport malloc, free, realloc, qsort
from libc.string cimport memcpy, memset, strlen, strcmp
from libc.math cimport sqrt, sin, cos, log, exp, fabs, pow
from libc.stdio cimport printf, fprintf, fopen, fclose
malloc çağrısı yaparken exception fırlatılırsa free atlıyabilir. Güvenli pattern: değişkeni NULL ile başlat, sonunda if ptr != NULL: free(ptr). Büyük modüllerde cdef class ve __dealloc__ daha güvenli bir alternatif sunar (bkz. Bölüm 05).
05 Extension types: cdef class
Python class'ının C-backed versiyonu: attribute'lar Python dict'te değil C struct'ta saklanır.
from libc.math cimport sqrt
cdef class Vector2D:
cdef public double x # Python'dan okuma ve yazma
cdef public double y
def __cinit__(self, double x, double y):
# C-level init — her koşulda çalışır, override edilemez
self.x = x
self.y = y
def __repr__(self):
return f"Vector2D({self.x}, {self.y})"
cpdef double magnitude(self):
return sqrt(self.x * self.x + self.y * self.y)
cpdef double dot(self, Vector2D other):
return self.x * other.x + self.y * other.y
def normalize(self):
cdef double m = self.magnitude()
if m == 0.0:
raise ValueError("Sıfır vektörü normalize edilemez")
return Vector2D(self.x / m, self.y / m)
Attribute erişim belirleyicileri
Lifecycle metodları
__cinit__ |
C-level initialize. __init__'den önce çalışır. Alt sınıf tarafından override edilemez; her zaman çağrılır. malloc çağrıları buraya. |
__init__ |
Normal Python init. Sonra çalışır, override edilebilir. |
__dealloc__ |
C-level destruktör. Python GC devreye girmeden önce çalışır. free() çağrıları buraya — Python exception güvenli. |
Manuel bellek yöneten cdef class örneği
from libc.stdlib cimport malloc, free
cdef class IntBuffer:
cdef int* data
cdef public int size
def __cinit__(self, int size):
self.size = size
self.data = <int*>malloc(size * sizeof(int))
if self.data == NULL:
raise MemoryError()
def __dealloc__(self):
if self.data != NULL:
free(self.data) # nesne yok edildiğinde otomatik çalışır
def __setitem__(self, int i, int val):
if i < 0 or i >= self.size:
raise IndexError(i)
self.data[i] = val
def __getitem__(self, int i):
if i < 0 or i >= self.size:
raise IndexError(i)
return self.data[i]
cdef class kısıtlamaları
- Monkey-patch yapılamaz —
v.new_method = lambda: ...çalışmaz - Sadece
cdef class'tan veyaobject'ten kalıtım alınabilir - C-tipli attribute'lar
__dict__'te görünmez;publicyapılmadan pickle edilemezler - Çoklu kalıtım kısıtlı: birden fazla
cdef class'tan miras alınamaz
06 cdef extern: C kütüphanesi sarmak
Mevcut bir C kütüphanesini hiç Python yazmadan Python'a açmak — cdef extern from ile.
libc fonksiyonlarını sarmak
cdef extern from "math.h":
double sin(double x) nogil
double cos(double x) nogil
double sqrt(double x) nogil
def py_sin(double x):
return sin(x) # doğrudan C sin() çağrısı
Kendi C kodunu sarmak
Önce C fonksiyonunu yaz:
// stats.c
#include "stats.h"
#include <stdlib.h>
double mean(const double* data, int n) {
double sum = 0.0;
for (int i = 0; i < n; i++) sum += data[i];
return sum / n;
}
double variance(const double* data, int n) {
double m = mean(data, n), v = 0.0;
for (int i = 0; i < n; i++) v += (data[i]-m)*(data[i]-m);
return v / n;
}
double mean(const double* data, int n);
double variance(const double* data, int n);
cdef extern from "stats.h":
double mean(const double* data, int n) nogil
double variance(const double* data, int n) nogil
def py_mean(list data):
cdef int n = len(data)
cdef double* arr = <double*>malloc(n * sizeof(double))
from libc.stdlib cimport malloc, free
if arr == NULL: raise MemoryError()
try:
for i in range(n): arr[i] = data[i]
return mean(arr, n)
finally:
free(arr)
setup.py — C kaynağını derlemeye dahil et
from setuptools import setup, Extension
from Cython.Build import cythonize
ext = Extension(
"pystats",
sources=["pystats.pyx", "stats.c"], # hem .pyx hem .c
libraries=["m"], # -lm (libm)
)
setup(ext_modules=cythonize([ext], language_level=3))
.pyx ve .c birlikte"m" = libm, "z" = libz, vb.)["./include"])["/usr/local/lib"])["-O3", "-march=native"])Hata işleme: except bildirimleri
# C fonksiyon -1 dönerse Python exception oluştur
cdef int might_fail(int x) except -1:
...
# Herhangi bir dönüş değerinde PyErr kontrolü yap (yavaş)
cdef int uncertain(int x) except? -1:
...
# void fonksiyon — her çağrıdan sonra kontrol et
cdef void also_might_fail(int x) except*:
...
Struct sarmak
cdef extern from "mylib.h":
ctypedef struct MyRecord:
int id
double value
char* label
MyRecord* record_new(int id, double val) except NULL
void record_free(MyRecord* r)
07 NumPy interop ve typed memoryview
NumPy dizilerine sıfır kopyalı erişim — Cython'un gerçek kullanım anı.
Typed memoryview nedir?
Typed memoryview, Python'un buffer protokolünü uygulayan her nesneye (NumPy array, array.array, bytes, bytearray) C seviyesinde, kopyasız erişim sağlar. NumPy import etmek zorunda bile değilsiniz — sadece bir array gelirse çalışır.
def matmul(double[:, :] A, double[:, :] B, double[:, :] C):
"""C = A @ B (in-place, C önceden sıfırlanmış olmalı)"""
cdef int i, j, k
cdef int M = A.shape[0]
cdef int K = A.shape[1]
cdef int N = B.shape[1]
for i in range(M):
for j in range(N):
for k in range(K):
C[i, j] += A[i, k] * B[k, j]
import numpy as np
import matmul
A = np.random.rand(100, 100)
B = np.random.rand(100, 100)
C = np.zeros((100, 100))
matmul.matmul(A, B, C) # sıfır kopya — A,B,C bellekte tutulur
Contiguity (bellek düzeni)
# cython: boundscheck=False, wraparound=False
def matmul_fast(double[:, ::1] A,
double[:, ::1] B,
double[:, ::1] C):
cdef int i, j, k
cdef int M = A.shape[0], K = A.shape[1], N = B.shape[1]
for i in range(M):
for j in range(N):
for k in range(K):
C[i, j] = C[i, j] + A[i, k] * B[k, j]
Benchmark (100×100, tek iş parçacığı)
# Saf Python döngüsü:
~8500 µs (85 ms)
# Typed memoryview, boundscheck açık:
~180 µs
# Typed memoryview [:, ::1], boundscheck=False:
~38 µs
# NumPy @ operatörü (BLAS):
~6 µs ← BLAS paralel SIMD kullandığı için kazanır
NumPy'nin kendi operatörleri (@, np.dot, np.sum) zaten BLAS/LAPACK üzerinde çalışır — paralel SIMD var. Cython memoryview, NumPy'nin ifade edemediği karmaşık element-wise logic için parlar: koşullular, birden fazla dizi üzerinde özel işlem, erken çıkış gerektiren döngüler.
Eski yöntem (legacy)
# Bu yöntem çalışır ama artık önerilmiyor
import numpy as np
cimport numpy as np
def old_style(np.ndarray[np.float64_t, ndim=2] A):
cdef int i, j
for i in range(A.shape[0]):
for j in range(A.shape[1]):
A[i, j] *= 2.0
Bu sözdizimi hâlâ geçerli ama typed memoryview daha az import, daha geniş uyumluluk ve daha temiz hata mesajları verir. Yeni kod için memoryview kullanın.
08 GIL ve paralellik: nogil + prange
GIL'i bırak, birden fazla çekirdeği kullan — ama kurallara uy.
GIL hatırlatması
CPython'un Global Interpreter Lock'u tek seferde yalnız bir thread'in Python bytecode'u çalıştırmasına izin verir. Bu, saf Python ile gerçek paralel CPU işlemi imkânsız kılar. Cython bu kısıtlamayı kısmen aşar: Python nesnelerine dokunmayan fonksiyonlar GIL'siz çalışabilir.
nogil fonksiyon
from libc.math cimport sin, sqrt
# GIL gerektirmeyen saf hesaplama
cdef double heavy_compute(double x) nogil:
return sin(x) * sqrt(x + 1.0)
# Python'dan çağrılabilir wrapper
def compute_single(double x):
return heavy_compute(x) # GIL otomatik tutulur
# Uzun hesaplama — GIL'i geçici bırak
def compute_many(double[:] data, double[:] out):
cdef int i, n = data.shape[0]
with nogil: # bu blok içinde GIL yok
for i in range(n):
out[i] = heavy_compute(data[i])
nogil içinde yasak ve izinli
| YASAK | Python nesnesi oluşturmak (list(), dict(), str), Python attribute erişimi, raise, print, Python fonksiyonu çağırmak, import |
| İZİNLİ | C tipleri, typed memoryview erişimi, cdef class C-tipli attribute'ları, cdef nogil fonksiyon çağrıları, libc fonksiyonları, printf |
| GİL GEREKİRSE | with gil: bloğu kullanarak nogil bölge içinde geçici GIL geri al |
prange ile paralel döngü
from cython.parallel cimport prange
def parallel_compute(double[:] data, double[:] out):
cdef int i, n = data.shape[0]
# GIL olmadan OpenMP ile paralel döngü
for i in prange(n, nogil=True, schedule='static'):
out[i] = heavy_compute(data[i])
def parallel_sum(double[:] data) -> double:
cdef int i, n = data.shape[0]
cdef double total = 0.0
# Cython reduction'ı otomatik tespit eder
for i in prange(n, nogil=True):
total += data[i]
return total
OMP_NUM_THREADS ortam değişkenisetup.py — OpenMP desteği
from setuptools import setup, Extension
from Cython.Build import cythonize
ext = Extension(
"parallel",
sources=["parallel.pyx"],
extra_compile_args=["-fopenmp"],
extra_link_args=["-fopenmp"],
)
setup(ext_modules=cythonize([ext], language_level=3))
macOS: Apple Clang OpenMP desteği varsayılan kapalıdır. brew install libomp ve -Xclang -fopenmp -lomp flagleri gerekir. Windows: MSVC /openmp flag'i ile.
Paralel blok içinde aynı bellek konumuna farklı thread'lerden yazma data race'e yol açar. total += data[i] gibi reduction ifadelerini Cython otomatik güvenli hale getirir — ama özel bir pointer veya buffer'a iki thread aynı anda yazmamalı. Okuma her zaman güvenli.
09 Performans tuning: annotate + direktifler
Neyin yavaş olduğunu görmek — cython -a sarısını avla, direktiflerle söndür.
Annotate HTML
cython -a matmul.pyx
# matmul.html dosyası üretildi
xdg-open matmul.html # ya da tarayıcıda aç
Her satır bir renk alır:
| Sarı (koyu) | Bu satır Python C-API çağrısı içeriyor — potansiyel yavaşlık. Satıra tıklayınca üretilen C kodu görünür |
| Beyaz | Saf C kodu — Python overhead yok |
Sarı satır gördüğünde şunu sor: bu değişkene/argümana tip eklenebilir mi? Evet ise ekle, yeniden derle, rengine bak. Bu döngüyü tekrarla.
Compiler direktifleri
# cython: language_level=3
# cython: boundscheck=False
# cython: wraparound=False
# cython: cdivision=True
# cython: initializedcheck=False
def matmul_opt(double[:, ::1] A,
double[:, ::1] B,
double[:, ::1] C):
cdef int i, j, k
cdef int M = A.shape[0], K = A.shape[1], N = B.shape[1]
for i in range(M):
for j in range(N):
for k in range(K):
C[i, j] = C[i, j] + A[i, k] * B[k, j]
a[100] boyutu 50 olan dizide segfault üretebilir. Profilleme doğrulandıktan sonra aça[-1]) desteğini kapat. Döngüde kullanılmıyorsa güvenli-5 // 2 = -3 yerine -2cdef class değişkeninin None olup olmadığı kontrolünü kapatTek fonksiyon için dekoratör
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def hot_loop(double[:] data):
cdef int i, n = data.shape[0]
for i in range(n):
data[i] *= 2.0
Önce/Sonra benchmark (100×100 matmul)
| Naive Cython (tip yok) | ~4200 µs |
| Tipli, boundscheck açık | ~180 µs — 23× hızlanma |
| + boundscheck=False | ~95 µs — ek 2× |
| + wraparound=False, C-contig | ~38 µs — ek 2.5× |
| + prange (4 çekirdek) | ~12 µs — ek ~3× |
Profil desteği
# cython: profile=True
# Derle, sonra cProfile ile çalıştır
python -m cProfile -s cumtime myscript.py
profile=True her fonksiyon çağrısında overhead ekler. Sadece profil sırasında açın, production build'de kapatın.
Önce profille, sonra optimize et. Direktifleri körü körüne açmak segfault, yanlış hesaplama veya integer overflow getirebilir. Annotate HTML'iyle doğrula, timeit ile ölç, sonra direktif aç.
10 Build sistemleri ve dağıtım
Geliştirmeden PyPI'a — setup.py, pyproject.toml ve wheel üretimi.
Tam setup.py — tüm seçenekler
from setuptools import setup, Extension
from Cython.Build import cythonize
ext = Extension(
name="mymod",
sources=["mymod.pyx", "helper.c"],
include_dirs=["./include"],
library_dirs=["/usr/local/lib"],
libraries=["m"],
extra_compile_args=["-O3", "-fopenmp", "-march=native"],
extra_link_args=["-fopenmp"],
)
setup(
name="mymod",
ext_modules=cythonize(
[ext],
language_level=3,
annotate=True, # setup sırasında da HTML üret
compiler_directives={
"boundscheck": False,
"wraparound": False,
}
)
)
Pyproject.toml (modern)
[build-system]
requires = ["setuptools>=64", "cython>=3.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mymod"
version = "0.1.0"
requires-python = ">=3.8"
pyproject.toml build-backend'i bildirir; Extension detayları hâlâ setup.py'da kalabilir ya da setup.cfg + setuptools.build_meta hook'larıyla pure-toml çözüme geçilebilir.
pyximport — geliştirme modu
import pyximport
pyximport.install(
language_level=3,
setup_args={"include_dirs": ["./include"]}
)
import mymod # .pyx değiştiyse otomatik yeniden derlenir
Dağıtım: sdist ve wheel
pip install build
# Source distribution (tarball)
python -m build --sdist
# dist/mymod-0.1.0.tar.gz içinde: .pyx + üretilmiş .c
# Kullanıcıda Cython yoksa .c'den derler — yeterlidir
# Binary wheel (platform-özel)
python -m build --wheel
# dist/mymod-0.1.0-cp311-cp311-linux_x86_64.whl
# İçinde: derlenmiş .so — kurulumda derleme gerekmez
Çoklu platform wheel: cibuildwheel
pip install cibuildwheel
# Yerel: sadece mevcut platform
cibuildwheel --platform linux .
# CI'da (GitHub Actions): Linux × macOS × Windows × Python 3.8–3.12
- uses: pypa/cibuildwheel@v2
with:
package-dir: .
output-dir: wheelhouse
env:
CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*"
sdist içine .c dosyasını dahil etmek
include *.pyx
include *.c
include *.h
.c dosyasını kaynak kontrolüne eklemek tartışmalıdır ama sdist kullanıcılarının Cython'a ihtiyaç duymaması için yaygın bir pratiktir.
11 Özet, karşılaştırma, köprü
Eğitim boyunca öğrendiklerinin kompakt formu.
def / cdef / cpdef karar ağacı
Python'dan çağrılacak mı? │ ├── Evet │ └── Cython içinden de hızlı çağrılsın mı? │ ├── Evet → cpdef │ └── Hayır → def (tip bildirimleri ekleyerek hızlandır) │ └── Hayır (sadece iç hesaplama) └── cdef (en hızlı, Python'dan görünmez)
Wire type tablosu (hızlı başvuru)
int / long / unsigned int | Tamsayı aritmetiği. long 64-bit Linux/macOS'ta en güvenli |
double / float | 64-bit / 32-bit kayan nokta. NumPy float64/float32 ile birebir |
bint | Boolean — C int olarak saklanır, Python bool döner |
size_t | Platform boyutu; malloc/sizeof argümanları için standart |
T[:] | 1D typed memoryview — herhangi düzen |
T[:, ::1] | 2D C-contiguous memoryview — NumPy default |
T* | Pointer — malloc/free ile birlikte, cdef class'ta __dealloc__'da free et |
Direktifler özeti
boundscheck=False | Dizi sınır kontrolü kapat → segfault riski, büyük kazanç |
wraparound=False | Negatif indeks desteği kapat → küçük kazanç |
cdivision=True | C bölme semantics → Python'dan farklı işaret davranışı |
initializedcheck=False | Memoryview geçerlilik kontrolü kapat |
profile=True | cProfile desteği ekle — sadece profil sırasında aç |
language_level=3 | Her zaman açık olsun — Python 3 semantics zorunlu |
protoc komut başvurusu (build)
python setup.py build_ext --inplace | Modülü derle, yanına koy |
cython -a file.pyx | Annotate HTML üret — sarı satırları avla |
cython --version | Cython sürümünü göster |
python -m build --wheel | Dağıtılabilir binary wheel üret |
python -m build --sdist | Kaynak dağıtımı üret (.pyx + .c dahil) |
Alternatifler — ne zaman hangisi?
| Cython | Mevcut Python kodunu kademeli hızlandır; C kütüphanesi sar; NumPy post-processing; GIL release + paralel döngü. Build pipeline masrafını ödemeye hazırsan. |
| numba | Pure Python + NumPy döngüsünü sıfır değişiklikle hızlandırmak. @jit dekoratörü yeter. Derleme zamanı ilk çağrıda olur. |
| ctypes | Mevcut bir .so/.dll'i derleme olmadan çağırmak. Hızlı prototip için yeter. |
| cffi | ctypes'tan daha temiz FFI; PyPy ile de çalışır. ABI ve API modu. |
| pybind11 | C++ kütüphanesini Python'a aç. C++ yazıyorsan doğal seçim. |
| PyO3 | Rust yazıyorsan ya da Rust öğrenmek istiyorsan. Bellek güvenliği ücretsiz. |
Öğrendiklerimiz
.pyx→ C →.soderleme zinciri;setup.py+cythonize()def/cdef/cpdeffarkı ve ne zaman hangisi- Struct, union, ctypedef, pointer ve
malloc/freebellek yönetimi cdef class:__cinit__,__dealloc__, typed attribute'larcdef extern fromile mevcut C fonksiyonları ve struct'ları sarmak- Typed memoryview (
double[:, ::1]) ile NumPy'ya sıfır kopyalı erişim nogilveprangeile paralel döngü, OpenMP kurulumucython -aile annotate HTML ve compiler direktifleri- sdist / wheel / cibuildwheel ile çoklu platform dağıtımı
Sonraki adım
Bu eğitim Cython'u sıfırdan kullanılabilir hale getirdi. Servisinize gRPC arayüzü eklemek istiyorsanız gRPC eğitimi'ne; veri formatı tanımlamak için Protocol Buffers eğitimi'ne geçebilirsiniz.