تا اینجا یاد گرفتیم async و await چطور باعث میشن چند تا کار رو همزمان انجام بدیم. ولی پشت صحنه چه کسی همهٔ این کارها رو مدیریت میکنه؟ پاسخ سادهاش اینه که یه چیزی به اسم event loop مسئول همهچیزه.
حلقهٔ رویداد یا همون event loop مثل یه مدیر پرجنبوجوشه که دائم بین کارها میچرخه و میگه:
«کدوم coroutine الان آمادهست اجرا بشه؟ کدوم باید منتظر بمونه؟»
در واقع event loop یه جور زمانبندیکنندهست. مطمئن میشه که هیچ کار بیدلیلی متوقف نشه و CPU هم همیشه مشغول باشه.
فرض کن توی خونه داری چای درست میکنی و سه تا کار داری:
- جوشوندن آب
- دم کردن چای
- آوردن لیوان
تو یه نفر بیشتر نیستی، ولی میتونی بین این کارها جابهجا بشی. وقتی آب روی گازه و هنوز نجوشیده، لازم نیست بایستی و فقط نگاهش کنی. میری لیوانها رو آماده میکنی، بعد برمیگردی سراغ چای. این همون کاریه که event loop تو برنامه انجام میده.
event loop یه صف از coroutineها داره. هر بار یکی از اونها اجرا میشه تا جایی که به یه نقطهٔ انتظار برسه (مثلاً وقتی از await استفاده میکنی). در اون لحظه، loop اونو کنار میذاره و سراغ کار بعدی میره. وقتی زمان اون coroutine رسید، دوباره برش میگردونه تو صف و ادامه میده.
همین جابهجایی مداوم باعث میشه همهٔ کارها ظاهراً همزمان پیش برن.
یه مثال ببین:
import asyncio
async def task(name, delay):
print(f"{name} started")
await asyncio.sleep(delay)
print(f"{name} finished after {delay} seconds")
async def main():
loop = asyncio.get_running_loop()
print("Event loop started:", loop)
await asyncio.gather(
task("Task A", 2),
task("Task B", 3),
task("Task C", 1)
)
print("All tasks completed!")
asyncio.run(main())در اینجا حلقهٔ رویداد همهٔ کارها رو با هم شروع میکنه. هرکدوم که به sleep میرسن، کنار گذاشته میشن تا زمانشون تموم بشه، و در این بین بقیه کارها اجرا میشن. در نهایت وقتی همه تموم شدن، پیام آخر چاپ میشه.
فرض کن برنامهای داری که باید چند تا کار زمانبر انجام بده، مثلاً:
- دریافت داده از API
- ذخیرهٔ اطلاعات توی پایگاه داده
- ارسال ایمیل برای کاربر
اگه بخوای این کارها رو به شکل عادی و پشت سر هم انجام بدی، باید برای هر کدوم صبر کنی تا تموم شه و این باعث میشه زمان زیادی از دست بره. ولی با event loop، میتونی همهٔ این کارها رو همزمان انجام بدی و از زمان انتظار یکی برای انجام دادن دیگری استفاده کنی.
داخل حلقهٔ رویداد چند بخش مهم وجود داره:
- صف آمادهها (Ready Queue): coroutineهایی که الان میتونن اجرا بشن.
- صف منتظرها (Waiting Queue): coroutineهایی که منتظر یه رویدادن (مثلاً پاسخ سرور یا گذشت زمان).
- بخش بیدارباش (Wakeup): وقتی یکی از coroutineها آماده میشه، از صف انتظار خارج میشه و برمیگرده به صف آمادهها.
این چرخه تا وقتی کارها تموم نشن ادامه داره. به همین دلیل بهش میگن حلقه.
پایتون اجازه میده خودت event loop فعلی رو ببینی:
import asyncio
async def show_loop():
loop = asyncio.get_running_loop()
print("Current loop:", loop)
asyncio.run(show_loop())این کد یه نمونه از event loop فعلی رو برمیگردونه که وظیفه داره coroutineها رو مدیریت کنه. معمولاً نیازی نیست خودت باهاش مستقیم کار کنی، چون asyncio همهچیز رو خودکار کنترل میکنه.
تابع asyncio.run در واقع خودش یه event loop موقتی میسازه، coroutine اصلی رو داخلش اجرا میکنه، و بعد از پایان، اون حلقه رو میبنده. این یعنی در هر لحظه فقط یه loop فعاله. اگه خودت یه loop جداگانه بسازی، باید مطمئن باشی داری کنترل کاملش رو در دست میگیری.
- حلقهٔ رویداد مغز پشت سیستم غیرهمزمان پایتونه.
- وظیفهٔ اون زمانبندی coroutineها و جابهجایی بینشونه.
- با event loop میشه چند کار رو همزمان انجام داد بدون اینکه برنامه قفل کنه.
- تابع asyncio.run خودش یه event loop میسازه و بعد از پایان کار اونو میبنده.