3.1 asyncio
modulu
Asinxron alt tapşırıqlar üçün öz thread-lərini yaradıb istifadə edənlər artıq çox azdır. Düzdür, onları yaratmaq olar, amma belə üsullar çox aşağı səviyyəli hesab olunur və yalnız framework yaradıcıları tərəfindən istifadə olunur. O da, başqa cür mümkün olmadıqda.
Hal-hazırda trenddə asinxron proqramlaşdırma, async/await
operatorları və korutinalar ilə task-lardır. Amma hər şeyi sırayla danışaq…
Bir az tarix
Əvvəllər Python-da asinxron proqramlaşdırma problemlərini həll etmək üçün korutinalar-dan istifadə olunurdu, bunlar generatorlara əsaslanırdı. Daha sonra, Python 3.4-də asyncio
(bəzən async IO
kimi yazılır) modulu təqdim edildi, hansı ki asinxron proqramlaşdırma mexanizmlərini təqdim edir. Python 3.5-də isə async/await
konstruktoru əlavə olundu.
İndi isə bir az giriş məlumatı. Əvvəlcə bu şeylər haqqında qısa danışacağam, sonra daha ətraflı, sonra isə daha da ətraflı. Çünki, demək olar ki, hamısı bir-biri ilə əlaqəli işləyir və bir anlayışın iş prinsipini digərinə istinad etmədən izah etmək mümkün deyil.
asyncio
modulu
asyncio
modulu asinxron proqramlar yazmaq üçün nəzərdə tutulub, burada tapşırıqları paralel yerinə yetirmək mümkündür. Modul, asinxron I/O əməliyyatlarını, timerləri, socket-ləri, korutina icrasını və çox thread-lərin idarə edilməsini dəstəkləyir, həm bir, həm də bir neçə Event Loop-da işləyə bilir.
Korutinalar (Coroutines)
Korutinalar — bu asinxron funksiyalardır, hansılar ki async def
açar sözü ilə təyin olunur. Korutinalar await açar sözü ilə öz icrasını dayandırmaq
imkanını verir, bu da digər korutinaların bu vaxt ərzində icrasına imkan verir
.
import asyncio
# Asinxron funksiyanın təyini (korutina)
async def main():
print('Salam ...')
# 1 saniyəlik icranı dayandırırıq
await asyncio.sleep(1)
print('... Dünya!')
# Asinxron funksiyanı Event Loop-da başlatmaq
asyncio.run(main())
Event Loop (Dövr)
Event Loop korutinaların, task-ların və digər asinxron əməliyyatların icrasını idarə edir. asyncio.run()
çağrışı dövrü başlatır və korutinaları tamamlamağa qədər icra edir.
import asyncio
async def main():
print('Salam ...')
await asyncio.sleep(1)
print('... Dünya!')
# Hazırkı Event Loop-u əldə edirik
loop = asyncio.get_event_loop()
# Korutinaları tamamlamağa qədər işlədirik
loop.run_until_complete(main())
# Event Loop-dan çıxırıq bütün task-ları tamamlandıqdan sonra
loop.close()
Task-lar (Tasks)
Task-lar korutinaları paralel şəkildə işə salmağa imkan verir. Onlar asyncio.create_task()
və ya asyncio.ensure_future()
ilə yaradılır.
import asyncio
# Gecikmə ilə işləyəcək korutina təyini
async def say_after(delay, what):
# İcranı təyin olunan müddətə dayandırırıq
await asyncio.sleep(delay)
print(what)
# Əsas korutina
async def main():
# Korutinaları paralel icra etmək üçün task yaradılır
task1 = asyncio.create_task(say_after(1, 'salam'))
task2 = asyncio.create_task(say_after(2, 'dünya'))
# Hər iki task-ın bitməsini gözləyirik
await task1
await task2
# Əsas korutina işə düşür
asyncio.run(main())
Future-lər (Futures)
Future
obyektləri, gələcəkdə mövcud olacaq asinxron əməliyyatların nəticələrini təmsil edir. Məsələn, asinxron task-ların tamamlanmasını gözləmək üçün istifadə olunur.
import asyncio
# Uzunmüddətli vəzifəni imitasiya edən korutina təyini
async def long_running_task():
print('Task başladı')
# 3 saniyəlik icranı dayandırırıq
await asyncio.sleep(3)
print('Task bitdi')
return 'Nəticə'
# Əsas korutina
async def main():
# Task-in bitməsini gözləyəcək Future yaradılır
future = asyncio.ensure_future(long_running_task())
# Task-i bitməsinə qədər gözləyirik və nəticəni alırıq
result = await future
print(f'Task nəticəsi: {result}')
# Əsas korutina işə düşür
asyncio.run(main())
3.2 Asinxron funksiya — async def
Asinxron funksiya adi funksiya kimi elan olunur, sadəcə def
açar sözündən əvvəl async
yazmaq lazımdır.
async def İsimFunktsiyası(parametrlər):
funksiyanın kodu
Asinxron funksiya adi funksiya kimi elan olunur, adi funksiya kimi çağırılır, amma nəticəni fərqli qaytarır. Əgər asinxron funksiyanı çağırsanız, o sizə nəticəni yox, xüsusi bir obyekt — korutina qaytaracaq.
Bunu hətta yoxlaya bilərsiniz:
import asyncio
async def main():
print("Hello World")
# Asinxron funksiyanın çağırılması, bu korutina qaytarır
result = main()
# Nəticənin tipini yoxlayırıq
print(type(result)) # <class 'coroutine'>
Nə baş verir? Əgər funksiyanı async sözü ilə işarələsəniz, əslində ona bir dekorator əlavə etmiş olursunuz ki, bu təxminən belə işləyir:
def async_decorator(func):
# Task obyektini yaradırıq
task = Task()
# Bizim func funksiyamızı onun hədəfi olaraq təyin edirik ki, icra etsin
task.target = func
# Task obyektini Tapşırıqlar növbəsinə daxil edirik — Event Loop
eventloop.add_task(task)
# Task obyektini qaytarırıq
return task
Kodunuz bu hala gəlir:
import asyncio
@async_decorator
def main():
print("Hello World")
result = main()
print(type(result)) # <class 'coroutine'>
Bu analoqun mənası budur:
Asinxron funksiyanı çağırdığınız zaman xüsusi bir Task
obyekti yaradılır ki, sizin funksiyanızı yerinə yetirəcək, amma nə vaxtsa, gələcəkdə. Bəlkə 0.0001 saniyədən sonra, bəlkə də 10 saniyədən sonra.
Bu task
obyekti (korutina) sizə dərhal asinxron funksiyanızın çağırılmasının nəticəsi kimi qaytarılır.
Bu korutina olur. Ola bilsin ki, sizin asinxron funksiyanız hələ yerinə yetirilməyə başlamayıb, amma task
obyekti (korutina) artıq sizdə var.
Niyə sizə bu task
(korutina) lazımdır? Onunla az şey edə bilərsiniz, amma 3 şeyi etmək mümkündür:
- Asinxron funksiya yerinə yetirilənə kimi gözləmək.
- Asinxron funksiya yerinə yetiriləndən sonra korutinadan funksiyanın nəticəsini almaq.
- 10 (istənilən sayda) asinxron funksiyaların yerinə yetirilməsini gözləmək.
Necə olduğunu aşağıda izah edəcəm.
3.3 await
operatoru
Korutin ilə bağlı əksər əməliyyatlar "asinxron funksiyanın yerinə yetirilməsini gözləməklə" başlayır. Buna görə də, bu əməliyyat üçün xüsusi bir await
operatoru var.
Sizin etməli olduğunuz tək şey onu korutinin qarşısında yazmaqdır:
await korutin
Və ya birbaşa asinxron funksiyanın çağırışının qarşısında:
await asinxron_funksiya(argumentlər)
Python kodda await
operatoruna rast gəldikdə, cari funksiyanın icrasını dayandırır və gözləyir ki, korutin icra olunsun — yəni korutinin istinad etdiyi asinxron funksiya tamamlanana qədər.
Vacibdir!
await
operatoru yalnız asinxron funksiya daxilində istifadə olunur ki, icra dayandırılsın və digər korutin və ya asinxron əməliyyat tamamlanana qədər gözlənsin.
Bu, asinxron funksiyaların çağırışları arasında keçidi sadələşdirmək üçün edilir. Belə bir await
çağırışı, əslində "nə qədər gözləyəcəyimizi bilmirik — digər asinxron funksiyaları icra etməkdə davam edin" deyən bir bəyanatdır.
Nümunə:
import asyncio
# Asinxron funksiyanın təyin olunması
async def async_print(text):
print(text)
# Əsas asinxron funksiya
async def main():
# Asinxron funksiyanın icrasını gözləmək üçün await istifadə olunur
await async_print("Salam Dünya")
# Hadisələr dövrünün işə salınması və main() korutinin icrası
asyncio.run(main()) #asinxron funksiyanı işə salır
Əslində await
operatoru daha incə işləyir — o, həmçinin çağırıldığı asinxron funksiyanın icra nəticəsini qaytarır.
Nümunə:
import asyncio
# İki ədədin cəmini hesablayan asinxron funksiyanın təyin olunması
async def async_add(a, b):
return a + b
# Əsas asinxron funksiya
async def main():
# async_add funksiyasının icra nəticəsini almaq üçün await istifadə olunur
sum = await async_add(100, 200)
print(sum)
# Hadisələr dövrünün işə salınması və main() korutinin icrası
asyncio.run(main()) #asinxron funksiyanı işə salır
Gəlin yekunlaşdıraq, await
operatoru:
- Cari asinxron funksiyanın, digər korutin və ya asinxron əməliyyat tamamlanana qədər icrasını dayandırır.
- Asinxron əməliyyatın və ya korutinin icra nəticəsini qaytarır.
- Yalnız asinxron funksiya daxilində istifadə edilə bilər.
GO TO FULL VERSION