8.2. Eşyordamlar ve görevler¶
Eşyordamlar (coroutines), bir asyncio programının inşa edildiği iş birimidir; görevler (tasks) ise bir uygulamanın birden çok eşyordamı eşzamanlı olarak çalıştırma şeklidir.
8.2.1. Eşyordamlar¶
Bir eşyordam (coroutine), async def ile bildirilen bir işlevdir:
import asyncio
async def heartbeat(interval_ms):
while True:
print("tick")
await asyncio.sleep_ms(interval_ms)
Gövde, fazladan tek bir bileşenle, sıradan bir işleve benzer: await. Eşyordamın bir şeyi beklemesi gereken her yerde – bir uyku, bir ağ okuması, ayarlanan bir olay – beklediği şey hazır olana kadar eşyordamı nasıl askıya alacağını bilen bir ifadeyi await eder. Her await noktasında eşyordam denetimi asyncio’ya geri verir; beklenen işlem tamamlandığında asyncio onu aynı noktadan devam ettirir.
Asyncio modülü iki uyku işlevi sunar:
asyncio.sleep()– argüman saniye cinsindendir, bir float kabul eder.asyncio.sleep_ms()– argüman milisaniye cinsindendir, bir int alır. Bir MicroPython uzantısıdır; aygıt yazılımındaki (firmware) zamanlama ayarları milisaniye biçiminde olduğundan genellikle kamerada doğru seçim budur.
Çıplak bir async def kendi başına hiçbir şey yapmaz. heartbeat(500) çağrısı gövdeyi yürütmez; asyncio’nun zamanlaması gereken bir eşyordam nesnesi döndürür. Bir eşyordamı zamanlamanın en basit yolu asyncio.run() işlevidir:
asyncio.run(heartbeat(500))
asyncio.run(), olay döngüsünü başlatır, kendisine verilen eşyordamı üst düzey giriş noktası olarak zamanlar, o eşyordam dönene kadar döngüyü çalıştırır, ardından döngüyü kapatır. Tek bir eşyordam için bu, programın tamamıdır. Birkaç eşyordam için uygulama görevlere başvurur.
8.2.2. Görevler¶
Bir görev (task), asyncio’nun bir eşyordamın etrafına sardığı, bunu geçerli olanla eşzamanlı olarak zamanla ve devam etmeme izin ver diyen bir sarmalayıcıdır. asyncio.create_task() bir tane oluşturur ve zamanlanan işi temsil eden bir Task nesnesi döndürür
task = asyncio.create_task(heartbeat("fast", 100))
Eşyordam artık döngünün zamanlamasındadır; çağıran onu beklememiştir. Döndürülen Task, çağıranın daha sonra o çalışan işle etkileşim kurmak için kullandığı tutamaçtır.
Uygulama tutamacı eline aldıktan sonra onunla üç şey yapabilir:
Görevin bitmesini bekle. Bir
Tasknesnesinin kendisi await edilebilir.result = await task,task‘ın eşyordamı dönene kadar geçerli eşyordamı askıya alır, ardından o eşyordamın döndürdüğü şeyle (ya da yükselttiği şeyi yeniden yükselterek) devam eder.Görevi iptal et.
task.cancel(), görevin eşyordamının içinde bir sonrakiawaitnoktasındaasyncio.CancelledErroryükseltilmesini zamanlar ve ona birfinallybloğunda temizlik kodu çalıştırma şansı verir. zaman aşımları ve iptal sayfası ayrıntıları kapsar.Daha sonra tanımla.
asyncio.current_task(), o anda çalışan eşyordam içinTasknesnesini döndürür. Çoğu betik onu hiç çağırmaz; ölçümleme ve istisna işleyicilerinde ortaya çıkar.
Betiğin tutamacı her seferinde yakalaması gerekmez. Uygulamanın başlatıp çalışmaya bıraktığı tek seferlik arka plan görevleri, dönüş değerini atabilir – döngü yine de onları zamanlar:
import asyncio
async def heartbeat(name, interval_ms):
while True:
print(name)
await asyncio.sleep_ms(interval_ms)
async def main():
asyncio.create_task(heartbeat("fast", 100))
asyncio.create_task(heartbeat("slow", 500))
await asyncio.sleep(5)
asyncio.run(main())
İki create_task çağrısı, her iki heartbeat’i de ikisinden birini beklemeden zamanlar. Denetim hemen main‘e döner ve ardından beş saniyelik bir uyku await edilir. O uyurken iki heartbeat görevi ilerleme kaydeder; döngü, çalışmaya hazır olan görevler arasında dolaşır. Beş saniye sonra main döner, döngü hâlâ canlı olan görevleri kapatır ve asyncio.run() çağırana döner.
Uygulama yukarıdaki üç işlemden birine gerçekten ihtiyaç duyduğunda tutamacı yakalayın. Pratikte bu, neredeyse her zaman anlamına gelir; çünkü bir uygulamayı temiz bir şekilde kapatmak, oluşturduğu arka plan görevlerini iptal etmek demektir – iptal sayfası bu deseni kapsar.
8.2.3. İki satır kuralı¶
Minimal asyncio programı, yukarıdaki örneklerin sonundaki iki satırdır
async def main():
...
asyncio.run(main())
Geri kalan her şey – uygulamanın oluşturduğu görevler, onları koordine ettiği ilkel yapılar, açtığı akışlar – main‘in içinde (ve main‘in oluşturduğu eşyordamların içinde) gerçekleşir. Bir betik, kameranın klasik while True: csi0.snapshot() döngüsünü aştığında, yanıt asyncio.run()‘ı birkaç yerde çağırmak değildir; yeni işi daha fazla görev olarak main‘in içine katmaktır.