8.1. İşbirlikçi eşzamanlılık¶
Asyncio’nun zamanlama modeli önleyici (preemptive) değil, işbirlikçidir (cooperative). Bu ayrım, bu bölümün geri kalanının üzerine inşa edildiği en önemli zihinsel modeldir; bu nedenle herhangi bir kod görünmeden önce netleştirmeye değer.
8.1.1. Önleyici (preemptive) vs işbirlikçi (cooperative)¶
Bir önleyici (preemptive) zamanlayıcı – bir masaüstü işletim sisteminin birçok programı aynı anda çalışır tutmak için kullandığı türden – o anda çalışan kod parçasını herhangi bir anda duraklatıp başka bir parçaya geçebilir. Çalışan kodun özel bir şey yapması gerekmez; zamanlayıcı onu keser. Bu, önleyici zamanlamayı çok esnek kılar (hiçbir kod parçası yavaş olarak diğerlerini açlığa sürükleyemez), ancak aynı zamanda her paylaşılan değişkenin dikkatlice korunması gerektiği anlamına gelir; çünkü geçiş herhangi bir yere – hatta bir değeri yazmanın ortasına ya da bir listeyi okumanın yarısına – denk gelebilir.
Bir işbirlikçi (cooperative) zamanlayıcı, kod parçaları arasında yalnızca o anda çalışan parçanın kontrolü açıkça geri verdiği noktalarda geçiş yapabilir. Asyncio’da bu noktalar, her await ve dahili olarak denetimi geri veren bir eşyordama (coroutine) yapılan her çağrıdır (en yaygın olarak asyncio.sleep()). İki await arasında, çalışan eşyordam CPU’yu yalnızca kendisi kullanır.
Bundan iki sonuç çıkar:
Hiç await yapmayan bir eşyordam asla duraklatılmaz. Bir eşyordam, içinde
awaitolmayan sıkı bir döngüde takılı kalırsa, zamanlayıcıyı tekeline alır ve başka hiçbir şey ilerleyemez. Çözüm, döngünün makul bir noktasındaawait asyncio.sleep_ms(0)(ya da başka bir bekleme çağrısı) yapmaktır.Paylaşılan durum await’ler arasında güvenlidir. İki eşyordam, içinde
awaitolmayan bir işlemin ortasında iç içe geçemez. Önlemenin çok adımlı bir güncellemenin ortasına denk geldiğinde ortaya çıkan türden bir bozulma – bir kod parçası bir değeri okurken diğerinin onu değiştirmenin yarısında olması – burada basitçe gerçekleşemez. Eşyordamlar arasında, birkaçının bir kaynağı await’ler boyunca paylaşması gerektiğinde yine de koordinasyon gerekir, ancak bir satırın ortasında iç içe geçme sorunu burada geçerli değildir.
8.1.2. Üç katman¶
Her asyncio betiği aynı üç katmandan oluşur. Sonraki iki sayfa bunları ayrıntılı olarak ele alır; bunlar onları okurken akılda tutulması gereken etiketlerdir.
Eşyordamlar (Coroutines) –
async defile bildirilen işlevler; her biri uygun yerlerde await yapan, kendi içinde bütünlüklü bir iş birimidir. Python Genel Bakış,async/awaitanahtar sözcüklerini tanıtmıştı; asyncio’da bunlar, bir eşyordamın denetimi zamanlayıcıya geri verme şeklidir.Görevler (Tasks) –
asyncio.create_task()işlevinin bir eşyordamın etrafına sardığı, onu geçerli olanla eşzamanlı olarak zamanlamak için kullanılan bir sarmalayıcıdır. Uygulama tipik olarak uzun süre çalışan işler (anlık görüntü döngüsü, ağ istemcisi, UART okuyucusu, …) için bir avuç görev oluşturur.Olay döngüsü (event loop) – altta yatan ve hangi eşyordamların beklediğini ve hangilerinin çalışmaya hazır olduğunu izleyen, her
awaitnoktasında görevler arasında geçiş yapan motordur. Uygulama döngüyü yazmaz; üst düzey bir eşyordamıasyncio.run()işlevine teslim eder ve döngü her şeyi oradan yönetir.
Uygulama bu şekilde – bir olay döngüsü tarafından bir araya getirilen küçük bir eşyordam kümesi olarak – tanımlandığında, eşzamanlılık programın biçiminin bir özelliği haline gelir, uygulamanın adım adım yönetmesi gereken bir şey değil.