Python'da `concurrent` Modülü
Bu makalede, Python'daki concurrent modülünü açıklayacağız.
Eşzamanlılık ve paralellik kavramlarını netleştirirken, pratik örneklerle concurrent modülünü kullanarak asenkron işlemenin nasıl gerçekleştirileceğini açıklayacağız.
YouTube Video
Python'da concurrent Modülü
Python'da işlemleri hızlandırırken, eşzamanlılık ve paralellik arasındaki farklara dikkat etmek önemlidir. concurrent modülü, bu farkları göz önünde bulundurarak asenkron işlemleri güvenli ve basit bir şekilde yönetmenin önemli bir yoludur.
Eşzamanlılık ile Paralellik Arasındaki Fark
-
Eşzamanlılık, sürecin küçük iş birimlerinde görevler arasında geçiş yaparak birden fazla görevin ilerleyebileceği şekilde tasarlanmasıdır. Görevler gerçekten aynı anda çalışmasa bile, "bekleme zamanı"nı kullanarak tüm süreci daha verimli hale getirebilirsiniz.
-
Paralellik, birden fazla görevi fiziksel olarak aynı anda çalıştıran bir mekanizmadır. Birden fazla CPU çekirdeği kullanılarak işlemler aynı anda yürütülür.
Her ikisi de işlemleri hızlandırmaya yönelik tekniklerdir, ancak eşzamanlılık 'nasıl ilerleyeceği' ile ilgili bir tasarım meselesiyken, paralellik 'nasıl çalışacağı' ile ilgili bir yürütme meselesidir; yani temelde farklıdırlar.
concurrent Modülü Nedir?
concurrent, Python'da eşzamanlılık ve paralellik işlemlerini güvenli ve basit bir şekilde yönetmek için yüksek seviyeli bir API sağlayan standart bir kütüphanedir. Thread veya süreç oluşturma ve yönetme gibi düşük seviyeli işlemlerle uğraşmadan, 'görevleri yürütmeye' odaklanabilmeniz için tasarlanmıştır.
ThreadPoolExecutor ve ProcessPoolExecutor'ün Rolleri
concurrent modülü, görevin doğasına bağlı olarak iki ana seçenek sunar.
-
ThreadPoolExecutorBu, özellikle ağ veya dosya işlemleri gibi çok fazla I/O beklemesi olan görevler için uygun bir eşzamanlılık uygulamasıdır. Görevler arasında geçiş yaparak, bekleme süresinin verimli kullanılmasını sağlar. -
ProcessPoolExecutorBu uygulama, paralel işlemeye yöneliktir ve CPU yoğun görevler için uygundur. Mevcut CPU çekirdeklerinden paralel olarak tam anlamıyla yararlanmak için birden fazla süreç kullanır.
Bu nedenle, concurrent modülünün ana özelliği, gerektiğinde eşzamanlılık ile paralellik arasında doğru seçim yapmanızı sağlayacak bir yapı sunmasıdır.
ThreadPoolExecutor Temelleri (I/O Görevleri İçin)
ThreadPoolExecutor ağ iletişimi ve dosya işlemleri gibi I/O odaklı görevler için uygundur. Görevleri birden fazla iş parçacığına dağıtarak, bekleme süresini verimli kullanır.
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in futures:
13 print(future.result())- Bu örnekte, bir saniye boyunca bekleyen birden fazla I/O görevi eşzamanlı olarak yürütülmektedir.
submitile fonksiyon çağrıları asenkron görevler olarak kaydedilir veresult()ile tamamlanmalarını bekleyip sonuçları alabilirsiniz. Bu şekilde bekleme süresini verimli kullanan eşzamanlı işlemler kısa bir şekilde gerçekleştirilebilir.
map Kullanarak Basit Eşzamanlılık
Karmaşık bir kontrol gerekmiyorsa, map kullanmak kodunuzu daha sade hale getirebilir.
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 results = executor.map(fetch_data, range(5))
11
12 for result in results:
13 print(result)- Bu örnekte, birden fazla I/O görevi
ThreadPoolExecutor.mapkullanılarak eşzamanlı olarak yürütülmektedir.map, girdilerle aynı sırada sonuçlar döndürdüğü için, neredeyse ardışık işleme yakın bir kod yazabilirsiniz ve asenkron işlemlerle uğraşmadan eşzamanlı yürütme mümkündür—bu önemli bir avantajdır.
ProcessPoolExecutor Temelleri (CPU Odaklı Görevler İçin)
CPU'yu tam olarak kullanan ağır hesaplamalar için iş parçacığı yerine süreç kullanmanız gerekir. Bu sayede Global Interpreter Lock (GIL) sınırlamasından kaçınabilirsiniz.
1from concurrent.futures import ProcessPoolExecutor
2
3def heavy_calculation(n):
4 # Simulate a CPU-bound task
5 total = 0
6 for i in range(10_000_000):
7 total += i * n
8 return total
9
10if __name__ == "__main__":
11 with ProcessPoolExecutor(max_workers=4) as executor:
12 results = executor.map(heavy_calculation, range(4))
13
14 for result in results:
15 print(result)Bu örnekte, CPU yoğun hesaplamalar ProcessPoolExecutor kullanılarak paralel olarak yürütülmektedir. Süreçlerin oluşturulması gerektiğinden, birden fazla CPU çekirdeği kullanarak güvenli paralel işlemeye olanak sağlayan bir __main__ koruması gereklidir.
as_completed ile Tamamlanma Sırasına Göre İşleme
as_completed, sonuçları tamamlanma sırasına göre işlemek istediğinizde yararlıdır.
1from concurrent.futures import ThreadPoolExecutor, as_completed
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in as_completed(futures):
13 print(future.result())- Bu örnekte, birden fazla asenkron görev aynı anda çalıştırılır ve sonuçlar tamamlanma sırasına göre alınır.
as_completedkullanmak, görev sıralamasından bağımsız olarak sonuçları hızlıca işlemenizi sağlar; bu da ilerleme göstergesi göstermek veya sırayla işlem gerektiren durumlar için uygundur.
İstisnaların Yönetimi
concurrent modülünde, result() çağrıldığında istisnalar meydana gelir.
1from concurrent.futures import ThreadPoolExecutor
2
3def risky_task(n):
4 # Simulate a task that may fail for a specific input
5 if n == 3:
6 raise ValueError("Something went wrong")
7 return n * 2
8
9with ThreadPoolExecutor() as executor:
10 futures = [executor.submit(risky_task, i) for i in range(5)]
11
12 for future in futures:
13 try:
14 print(future.result())
15 except Exception as e:
16 print("Error:", e)- Bu örnek, bazı görevler istisna oluştursa bile diğerlerinin çalışmaya devam ettiğini ve sonuçları alırken her istisnayı ayrı ayrı yönetebileceğinizi gösterir.
concurrent'ınFuture'ı sayesinde, asenkron işlemedeki başarı ve başarısızlıkların güvenle yönetilebilmesi önemlidir.
Thread ve Süreçler Arasında Seçim İçin Kılavuz
Eşzamanlılık ve paralelliği verimli kullanmak için, görevin niteliğine göre doğru yaklaşımı seçmek önemlidir.
Pratikte aşağıdaki ölçütler karar vermenize yardımcı olabilir.
- İletişim veya dosya işlemleri gibi çok fazla G/Ç beklemesi olan işlemler için
ThreadPoolExecutorkullanın. - CPU odaklı, ağır hesaplama gerektiren görevler için
ProcessPoolExecutorkullanın. - Birçok basit görev varsa,
mapkullanmak daha kısa kod yazmanızı sağlar. - Çalıştırma sırası veya istisna yönetimi üzerinde hassas kontrol gerekiyorsa,
submitileas_completed'ı birleştirin.
concurrent Kullanmanın Faydaları
concurrent modülünü kullanarak asenkron işlemleri güvenli ve sezgisel bir şekilde yönetebilirsiniz.
Başlıca faydalar şunlardır:.
- Düşük seviyeli iş parçacığı veya süreç yönetimiyle uğraşmak zorunda değilsiniz.
- Python'un standart kütüphanesinin bir parçası olarak sunulur, bu yüzden güvenle kullanabilirsiniz.
- Kod daha okunabilir ve sürdürülebilir hale gelir.
- Eşzamanlılık ve paralellik hakkında bilgi edinmek için ideal bir ilk adımdır.
Bu kılavuzlara dikkat etmek, concurrent kullanan uygulamalardaki hataları büyük ölçüde azaltabilir.
Özet
concurrent modülü, Python'da pratik eşzamanlılık ve paralellik için standart bir seçenektir. İşleminizin içeriğini büyük ölçüde değiştirmeden performansı artırmanıza olanak tanır; bu da gerçek uygulamada önemli bir faydadır. concurrent kullanarak asenkron işlemleri kısa bir şekilde uygulayabilir ve aynı anda istisna yönetimini ve çalışma kontrolünü güvenli bir şekilde sağlayabilirsiniz.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.