Her yazılımcı, doğru veri yapılarıyla ne kadar hızlı çalışabileceğini bilir. Yanlış veri yapısı seçimi, kodunuzun performansını doğrudan etkiler. Python’da, liste, küme, sözlük gibi veri yapıları çok yaygın kullanılır, ancak her biri farklı işlevler için daha verimli olabilir.
Örneğin, eğer sıralı verilere ihtiyaç duyuyorsanız, `list` yerine `tuple` kullanmak çok daha hızlı olabilir. Çünkü `tuple`lar, değiştirilemez oldukları için daha hızlı erişim sağlarlar. Aynı şekilde, arama işlemleri için `dict` veya `set` veri yapıları çok daha verimlidir, çünkü bunlar hash tabanlı yapılar kullanarak aramaları O(1) zaman karmaşıklığında gerçekleştirir.
Python’da bellek yönetimi çok önemlidir. Özellikle büyük veri setleriyle çalışırken, belleği verimli kullanmak ve işlemleri hızlandırmak gerekir. Burada devreye jeneratörler girer.
Jeneratörler, veri üretimini lazy evaluation ile yaparak bellek kullanımını ciddi şekilde azaltır. Örneğin, büyük bir listeyi belleğe yüklemek yerine jeneratör kullanarak her bir öğeyi gerektiğinde oluşturabilirsiniz. İşte bunun bir örneği:
def generate_numbers(n):
for i in range(n):
yield i
# Kullanım
for num in generate_numbers(1000000):
print(num)
Burada, tüm sayıları belleğe yüklemek yerine, her seferinde bir sayı üretiyoruz. Bu sayede bellek kullanımı minimum seviyeye indirilir.
Kodu optimize etmeden önce, performans darboğazlarını anlamanız gerekir. Python, kodunuzu analiz etmenizi sağlayacak çeşitli araçlar sunar. `cProfile` gibi araçlarla hangi fonksiyonların ne kadar süre çalıştığını görebilir ve problemin hangi kısmından kaynaklandığını anlayabilirsiniz.
Profiling yapmak için:
import cProfile
def slow_function():
total = 0
for i in range(1000000):
total += i
return total
cProfile.run('slow_function()')
Yukarıdaki örnekte, `cProfile` ile fonksiyonun ne kadar süre harcadığını analiz edebilirsiniz. Bu sayede, hangi fonksiyonların optimizasyon gerektirdiğini kolayca belirleyebilirsiniz.
Python’un Global Interpreter Lock (GIL) sınırlamaları nedeniyle, çoklu iş parçacığı kullanımı bazı durumlarda sınırlıdır. Ancak, işlem bazında paralel işlem yaparak çoklu çekirdeklerden faydalanabilirsiniz.
Bunu başarmanın en iyi yolu, Python’un `multiprocessing` modülünü kullanmaktır. Bu modül, her bir işlem için ayrı bir Python yorumlayıcısı çalıştırır, böylece her çekirdek bağımsız olarak çalışabilir. İşte bunun bir örneği:
from multiprocessing import Process
def worker(num):
print(f"Çalışan {num} başladığında")
if __name__ == '__main__':
processes = []
for i in range(5):
p = Process(target=worker, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
Bu kod, 5 farklı iş parçacığını başlatır ve her birini paralel olarak çalıştırır. Bu sayede işlem süresi ciddi şekilde azalır.
Birçok geliştirici, iç içe döngülerle uğraşırken kodun yavaşladığını fark eder. İç içe döngülerde yapılan her işlem, kodun karmaşıklığını artırır ve bu da zaman alır. Bunu minimize etmek için döngülerinizi optimize edebilirsiniz.
Örneğin, iki listeyi karşılaştırmak yerine, bir listeyi önceden bir sözlüğe dönüştürüp arama işlemini daha hızlı yapabilirsiniz:
list1 = [1, 2, 3, 4, 5]
list2 = [5, 4, 3, 2, 1]
# İç içe döngü kullanmak yerine
dict_list1 = {i: True for i in list1}
result = [i for i in list2 if dict_list1.get(i)]
print(result)
Bu yöntem, iç içe döngü kullanmaktan çok daha hızlıdır, çünkü `dict` veri yapıları aramaları daha verimli hale getirir.
Birçok Python uygulaması, veritabanlarına bağlanır ve veri çeker. Ancak, yanlış yapılandırılmış sorgular veya gereksiz veri çekme işlemleri performans sorunlarına yol açabilir. Veritabanı sorgularını optimize etmek, yalnızca ihtiyacınız olan verileri çekmek ve gereksiz işlemlerden kaçınmak önemlidir.
Eğer SQL sorgularınızda birden fazla JOIN kullanıyorsanız, bunları optimize etmeyi düşünün. Ayrıca, sorguları tek seferde çalıştırmak, yerine parçalara bölüp her birini ayrı ayrı çalıştırmak verimliliği artırabilir.
Python, performans açısından optimize edilmiş bir dizi dahili kütüphaneye sahiptir. Bu kütüphaneleri kullanarak yazacağınız kodu hızlandırabilirsiniz. Örneğin, sayısal işlemler için `NumPy` veya `Pandas` kullanmak, yerleşik Python listelerine göre çok daha hızlı ve verimlidir.
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
result = arr * 2
print(result)
Cython, Python kodunun C diline derlenmesini sağlayan bir araçtır. Bu, Python kodunun hızını büyük ölçüde artırabilir. PyPy ise Python’un daha hızlı bir yorumlayıcısıdır. Eğer performans ciddi bir konuysa, bu iki teknolojiyi de göz önünde bulundurabilirsiniz.
Performans iyileştirmeleri yapmak, sürekli bir süreçtir. Kodunuzu sık sık gözden geçirin ve refaktör edin. Daha temiz, daha anlaşılır ve daha hızlı bir kod yazmak her zaman uzun vadede fayda sağlar.
Herhangi bir optimizasyon işleminden sonra, geri dönüp kodunuzu tekrar test edin. Çünkü bazen bir optimizasyon, başka bir soruna yol açabilir. Performans testleri, yapılan değişikliklerin gerçekten faydalı olup olmadığını belirlemenize yardımcı olur.