Python Async neden hâlâ ana akım değil?
(tonybaloney.github.io)Python Async neden hâlâ ana akım değil?
Python’un asyncio yapısı, I/O (giriş/çıkış) işlemlerinin yoğun olduğu ortamlarda bekleme sürelerini azaltarak program verimliliğini dramatik biçimde artırabilen güçlü bir araçtır. Ancak pek çok avantajına rağmen tüm Python geliştiricileri tarafından aktif biçimde kullanılmıyor; bunun arkasında birkaç temel neden var.
1. Zihin yoruyor: bilişsel yük
En büyük engel karmaşıklıktır. Senkron kod sezgiseldir çünkü bir kitabı okur gibi yukarıdan aşağıya doğru yürütme akışını sırayla takip etmek yeterlidir.
Ama asenkron kod farklıdır. Bunu, tek bir aşçının makarna yaparken erişteler haşlanırken (bekleme süresi) bir yandan sos hazırlaması ve kalan zamanda sebzeleri doğraması gibi düşünebilirsiniz. Sonuçta yemek daha hızlı hazırlanabilir, ama aşçının zihninde sürekli olarak “Şu an makarna ne kadar pişti?”, “Sos yanıyor mu?” gibi birden fazla işin durumunu takip etmesi gerekir.
Kodun yürütme akışı bu şekilde sürekli bir yerden başka bir yere sıçradığı için, şu anda hangi işin çalıştığını ve hangisinin beklemede olduğunu anlamak zorlaşır. Bu da özellikle hata ortaya çıktığında, nedenini izlemeye yönelik hata ayıklama sürecini oldukça çetrefilli hale getirir.
2. Ayrışmış ekosistem: kütüphane uyumluluğu
Python’daki bir başka sorun da kütüphane ekosisteminin “senkron” ve “asenkron” olarak bölünmüş olmasıdır. Çok sayıda ünlü ve kullanışlı kütüphane (örneğin standart HTTP istek kütüphanesi requests veya birçok ORM) yalnızca senkron biçimde çalışır.
Asenkron kod içinde senkron bir kütüphane yanlış şekilde kullanılırsa, o senkron kod çalıştığı süre boyunca asenkron yapının en büyük avantajı olan “event loop” tamamen durur. Bu, birden fazla şerit yapıp yalnızca tek şeridi kullanmaya benzer; yani asenkron kullanmanın anlamı kalmaz. Bu sorunu çözmek için asenkronu destekleyen ayrı kütüphaneleri (aiohttp, asyncpg vb.) yeniden öğrenip uygulamak gerekir; bu da öğrenme eğrisini daha da dikleştirir.
3. Aynı anda tek iş: GIL (Global Interpreter Lock)
GIL (Global Interpreter Lock), Python’un kronik özelliklerinden biridir ve tek bir süreç içinde birden fazla thread olsa bile aynı anda yalnızca tek bir thread’in çalışmasına izin veren bir mekanizmadır. asyncio tek bir thread üzerinde çalıştığı için GIL ile doğrudan çatışmaz; ancak GIL’in varlığı async kullanım alanını sınırlar.
asyncio, I/O bekleme sürelerinden (ağ yanıtı bekleme, dosya okuma bekleme vb.) yararlanmak için optimize edilmiştir. Ancak eğer çok karmaşık hesaplamalar gerektiren CPU yoğun işler async fonksiyonunun içine girerse, bu hesaplama bitene kadar tüm event loop durur. Bu süre boyunca diğer I/O işleri hiçbir şey yapamadan beklemek zorunda kalır. Sonuç olarak, gerçek paralel işlem gerektiren işler için hâlâ multiprocessing gibi başka tekniklere başvurmak gerekir.
4. Geleceğe dair umut: Python 3.14 ve GIL’in kaldırılması
Ancak bu sınırlamalar konusunda oldukça umut verici bir gelişme var. Python 3.13 ile deneysel olarak sunulan ve 3.14 sürümünde daha olgun hale gelmesi beklenen GIL’in isteğe bağlı kaldırılması yönündeki adımlar bunların başında geliyor.
PEP 703 adlı öneriyle ilerletilen bu değişiklik, geliştiricilerin isterlerse Python kodunu GIL olmadan çalıştırabilmesini hedefliyor. Bu gerçekleşirse, Python’da birden fazla thread’in birden fazla CPU çekirdeğini aynı anda kullanabildiği gerçek çoklu iş parçacığı çalışması mümkün hale gelecektir.
Bu da asyncio ile birlikte kullanıldığında muazzam bir sinerji yaratabilir. I/O işleri asyncio ile verimli biçimde yürütülürken, yoğun hesaplama gerektiren CPU işleri ayrı thread’lere aktarılıp GIL kısıtı olmadan paralel işlenebilecektir. Bu değişimin Python ekosisteminde büyük bir dönüm noktası olması ve async programlamanın benimsenmesini engelleyen pek çok bariyeri ortadan kaldırması bekleniyor.
9 yorum
GIL biraz alakasız bir yerden çıkmış gibi görünüyor ama... GIL kaldırılsa bile
hem I/O bound hem de CPU bound durumlarda multithread kullanmak istiyorsanız
Python yerine başka bir alternatif benimsemek daha iyi olmayabilir mi...
asyncionun, Python’ı derinlemesine kullananlar arasında epey sevilmediği gibi bir his var gerçekten.geventin ana akım haline gelmesi gerektiği yönünde görüşleri ara sıra duyduğumu sanıyorum.Mevcut GIL konusundaki yönelimin, ‘diğer alternatiflerle’ karşılaştırıldığında bile hiç de geri kalmayacak bir hale geleceğini umamayacağımız konusunda hemfikirim,
ancak Python dışında başka bir alternatifi benimsememiz gerektiğini söylemenin, ortada bir sorun olmadığını savunan bir tona değil, bir sorun olduğunu savunan bir tona bağlanması gerekmez mi diye düşünüyorum.
asynciooldukça kullanılıyor.. işe yarıyor.. iş iptalinin edge-triggered (level-triggereddeğil) olması gibi bir sınırlaması var ama aslında iş iptalinin farkında olarak graceful işlem yapan kod yazmak çok sık karşılaşılan bir durum değil ve bundan daha büyük sorun,eventloop'un task'ler için weak reference tutması nedeniyle bunların gc tarafından ortadan kaldırılabilmesi ama.. bu da structured concurrency ile çözülüyor.Çoğu önemli I/O işiyle ilgili olarak
asynciodestekleyen kütüphane bulmakta da sorun yok..GIL? Bununla çok büyük bir ilgisi yok..
asyncio'yu CPU intensive işleri paralel yapmak için kullanma yaklaşımının kendisi biraz garip zaten.. GIL iyileşirse CPU intensive multithreading için faydalı olur tabii.. async ise I/O darboğazı olan bölümleri olabildiğince verimli döndürmek için var...Neyse, sonuç olarak.. tasarım açısından belli ölçüde sorunlar var ama amaca ulaşmak için kullanırken belirgin bir problem yaşamadan production'da gayet iyi kullanıyoruz.
gc tarafından task'lerin toplandığını hiç deneyimlediniz mi?
Elbette ben de production ortamında
asyncioyu bıkana kadar kullanıyorum ama şu anki kullanım deneyiminden, "iyi kullanıyorum" diyecek kadar memnun değilim..Mevcut
asyncio, bir bakıma GIL’den kaçınma stratejisi olarak GIL varsayımıyla tasarlandığı için, GILasyncioile doğrudan etkileşime girmez.Ama
asynciotabanlı çalışan eşzamanlılık programlamasının tamamı açısından bakınca, GIL’in alakasız olduğunu söylemenin "Python olduğu için olmaması zaten normal." demek gibi bir şey olduğunu düşünüyorum.Ben sadece joblib kullanacağım.
Asyncio’nun sorunu, zor asenkron programlamanın zorluğu değil; düşük kalite. Tutarlılığı ve evrenselliği bir kenara atan bu tasarım Python’da pek de nadir değil ama ProactorEventLoop gibi şeylerde, 5 yıl önce bildirilen ve hizmet kesintisine yol açan hatalar hâlâ duruyor.
Bunu mecburen kullanmak zorunda olan biri olarak, böyle yazılara gülüp geçmek gerçekten çok zor.
Elbette, GIL nedeniyle en başta elde edilebilecek faydanın diğer ortamlara kıyasla daha az olması daha büyük neden olabilir.
GIL yoksa sinerji yaratılabileceğini söylemenin aldatıcıya yakın olduğunu düşünüyorum. Tek bacağı olmayan bir koşucuya, rahatsız da olsa protez takınca buna 'sinerji' mi denir?