8.4. Gather¶
Önceki bölüm, asyncio.create_task()‘in bir eşyordamı nasıl zamanladığını ve onu beklemediğini gösterdi. Bunun eşlik eden işlemi – birkaç beklenebiliri eşzamanlı olarak çalıştırmak ve hepsini beklemek – asyncio.gather()‘dır.
8.4.1. Temel yapı¶
import asyncio
async def fetch(name, delay_ms):
await asyncio.sleep_ms(delay_ms)
return name
async def main():
results = await asyncio.gather(
fetch("a", 100),
fetch("b", 200),
fetch("c", 50),
)
print(results)
asyncio.run(main())
Çıktı:
['a', 'b', 'c']
Dikkat edilecek iki şey. İlki, sonuç listesi eşyordamların bittiği sıraya göre değil, gather’ın argümanlarının sırasına göredir – "c" ilk döndü ancak yine de üçüncü girdidir. İkincisi, çağrı 350 ms değil, toplamda 200 ms sürdü: üç uyku eşzamanlı olarak çalıştı ve gather() en yavaş olan tamamlanır tamamlanmaz döner.
Her iki olgu da aynı kaynaktan gelir. gather(), halihazırda görev olmayan her argümanı (örnekteki eşyordamlar) sarmalar, onları döngüde zamanlar, hepsi bitene kadar çağıran eşyordamı askıya alır, ardından sonuçlarını orijinal sırada döndürür.
8.4.2. Ne zaman başvurulmalı¶
Uygulamanın N beklenebilir işlemi olduğu ve devam etmeden önce hepsinin sonuçlarını istediği her yerde. Tipik örnekler:
Birkaç ağ isteğini paralel olarak gönderip tüm yanıtları beklemek.
Birleştirilmiş sonucu işlemeden önce birkaç sensörden eşzamanlı olarak okumak.
Bir uygulama aşamasının sonunda birkaç kısa ömürlü yardımcı görevi birleştirmek.
Uygulamanın başlatıp programın ömrü boyunca çalışır bıraktığı uzun süreli arka plan görevleri için doğru araç değildir – bunlar hâlâ create_task() işidir. gather(), yayma / toplama deseni içindir: işi böl, eşzamanlı olarak yap, yeniden birleştir.
8.4.3. Gruptaki istisnalar¶
Toplanan beklenebilirlerden herhangi biri istisna oluşturursa, varsayılan davranış istisnayı gather çağrısından dışarı yeniden oluşturmaktır. Henüz bitmemiş kardeşler arka planda iptal edilir.
Bu genellikle bir uygulamanın istediği şeydir – N paralel işten biri başarısız oldu, dolayısıyla birleştirilmiş işlem başarısız oldu, bu nedenle geri kalanına zaman harcamayı bırak. Bazen uygulama bunun tersini ister: her beklenebilirin bağımsız olarak bitmesine (veya başarısız olmasına) izin ver ve sonuçları sonradan incele. Bunun için return_exceptions=True geçirin:
results = await asyncio.gather(
fetch_or_fail("ok"),
fetch_or_fail("bad"),
return_exceptions=True,
)
# results == ["ok-value", OSError(...)]
Döndürülen listedeki her girdi artık ya normal bir dönüş değeri ya da ilgili beklenebilirin oluşturduğu istisnadır. Çağıran, onları ayırt etmek için isinstance(r, Exception) kontrolünü yapar.
8.4.4. İptal¶
Gather’ın kendisini iptal etmek – onu bekleyen görevi iptal ederek – içinde hâlâ çalışan her beklenebiliri iptal eder. zaman aşımları ve iptal sayfası, iptalin çağrı zinciri boyunca nasıl yayıldığını ayrıntılı olarak ele alır.