Giriş
Python yorumlanan bir dil olduğu için CPU yoğun döngülerde C veya Rust'a kıyasla yavaş görünebilir. Ancak çoğu uygulama I/O bound'dur; gerçek darboğazlar genelde verimsiz algoritma, gereksiz kopyalama veya N+1 sorgu gibi yazılım katmanı sorunlarıdır.
Bu yazıda cProfile ve line_profiler ile ölçüm, Big-O düşüncesi, NumPy vektörizasyonu, __slots__ ve Cython ile kritik yolların hızlandırılmasını ele alıyoruz. Premature optimization tehlikesine karşı önce ölç, sonra optimize et ilkesini benimsiyoruz.
cProfile ile Profiling
cProfile standart kütüphanede yer alır; fonksiyon çağrı sayısı ve kümülatif süreyi kaydeder. python -m cProfile -s cumtime script.py veya profile.Profile() ile programatik kullanım mümkündür. pstats modülü sonuçları sıralar ve filtreler.
snakeviz ve gprof2dot görsel flame graph üretir; hangi fonksiyonun toplam sürenin yüzde kaçını tükettiğini hızlıca görürsünüz. Üretimde cProfile overhead'i vardır; kısa süreli profil veya sampling profiler (py-spy) tercih edilir.
import cProfile
import pstats
with cProfile.Profile() as pr:
run_heavy_workload()
stats = pstats.Stats(pr)
stats.sort_stats(pstats.SortKey.CUMULATIVE)
stats.print_stats(20)line_profiler ve Bellek Profili
@profile dekoratörü (line_profiler paketi) satır satır süre gösterir; dar döngülerde hangi satırın maliyetli olduğunu netleştirir. kernprof -l -v script.py ile çalıştırılır.
memory_profiler @profile ile satır bazlı bellek kullanımı raporlar. tracemalloc snapshot karşılaştırması bellek sızıntısı avında kullanılır. CPU ve bellek profilini birlikte değerlendirmek, yanlış optimizasyon yönünü önler.
- cProfile: fonksiyon düzeyi CPU profili
- line_profiler: satır düzeyi CPU profili
- py-spy: sampling, düşük overhead
- tracemalloc: bellek tahsis izleme
Algoritma ve Veri Yapısı Optimizasyonu
O(n²) iç içe döngüyü O(n) set veya dict ile değiştirmek, Cython'dan daha büyük kazanç sağlayabilir. list yerine deque, membership test için set, sık arama için dict kullanın. Generator ile bellekte tüm listeyi tutmayın.
NumPy vektörizasyonu Python döngüsünden 10-100x hızlanma sağlayabilir. Pandas apply yerine vektörize operasyon tercih edin. ORM'de select_related ve prefetch_related N+1 sorguyu çözer.
Önce algoritmayı düzeltin; mikro optimizasyon ikinci plandadır.
Cython ile Hızlandırma
Cython, Python benzeri sözdizimini C'ye derleyerek tip annotation'ları sayesinde bounds check atlama ve doğrudan C API çağrısı sağlar. .pyx dosyası setup.py veya pyproject.toml ile derlenir; import edilen modül normal Python modülü gibi kullanılır.
cdef int, cdef double gibi statik tipler ve for döngüleri C hızına yaklaşır. Mevcut .py dosyasını %%cython magic (Jupyter) veya pyximport ile kademeli dönüştürmek mümkündür. NumPy array'leri memoryview ile sıfır kopya erişilir.
# example.pyx
cdef int fibonacci(int n):
cdef int a = 0, b = 1, i, tmp
for i in range(n):
tmp = a + b
a = b
b = tmp
return aAlternatifler: Numba ve PyPy
Numba @jit dekoratörü ile NumPy uyumlu fonksiyonlar LLVM ile makine koduna derlenir; bilimsel hesaplamada Cython'a alternatiftir. nopython=True modu Python fallback olmadan en hızlı yolu seçer.
PyPy JIT yorumlayıcısı saf Python döngülerinde CPython'dan hızlıdır; C extension uyumluluğu sınırlı olabilir. Kritik modül için Cython, tüm uygulama için PyPy veya seçili fonksiyon için Numba üçlüsünden iş yüküne göre seçim yapın.
- Saf Python döngü: PyPy veya Cython
- NumPy sayısal: vektörizasyon veya Numba
- I/O bound: asyncio veya paralel I/O
- CPU paralel: multiprocessing
Mikro Optimizasyon ve Kaçınılacaklar
Local variable erişimi global'den hızlıdır; sık kullanılan global'leri lokal'e bağlayın. join ile string birleştirme += döngüsünden üstündür. __slots__ instance dict maliyetini kaldırır.
Gereksiz list comprehension, lambda ve attribute lookup mikro kazanç sağlar; profil göstermeden uygulamayın. JSON için orjson, regex için regex modülü compile, serialization için msgpack gibi hızlı kütüphaneler domain'e özel kazanç verir.
# Yavas
result = []
for x in data:
result.append(process(x))
# Daha iyi
result = [process(x) for x in data]
# En iyi (vektorize mumkunse)
result = np.vectorize(process)(data)Sonuç
Python performansı ölçüm disiplini gerektirir: cProfile ile darboğazı bulun, algoritma ve veri yapısını iyileştirin, hâlâ yetersizse Cython veya Numba'ya geçin. Çoğu web API'si için veritabanı ve ağ optimizasyonu, Python mikro optimizasyonundan daha fazla kazandırır.
Performans bütçesi belirleyin: endpoint başına p99 gecikme hedefi, profil regression testi ve CI'da benchmark (pytest-benchmark) ile gerilemeyi erken yakalayın. Okunabilir kod ile hız arasında bilinçli denge kurun.