تسلط بر برنامه‌نویسی ناهمگام (Asyncio)درس 1 از 9

معماری ناهمگام و مفهوم Event Loop

گذر از بن‌بست‌های اجرایی (Blocking) و شناخت عمیق کوروتین‌ها

در برنامه‌نویسی سنتی یا «همگام» (Synchronous)، وقتی کدی به عملیاتی زمان‌بر (مثلاً درخواست از شبکه، دانلود فایل، یا خواندن دیتابیس) می‌رسد، کل برنامه‌ی شما و پردازنده متوقف می‌شود تا پاسخ دریافت گردد. این یعنی خطوط بعدی کد باید به اجبار منتظر بمانند که رم و پردازنده به شدت هدر می‌رود. اما با رویکرد «ناهمگام» (Asynchronous) توسط کتابخانه داخلی asyncio، در زمان انتظار یک عملیات، برنامه‌ی شما می‌تواند کنترل را رها کرده و به اجرای بخش‌ها و وظایف دیگر بپردازد!

حلقه رویداد (Event Loop) چیست؟

هسته مرکزی معماری Async در پایتون، **Event Loop** است. حلقه رویداد را می‌توان به یک سرآشپزِ بی‌نهایت فرز تشبیه کرد که روی ده‌ها قابلمه‌ی مختلف در حال پخت‌وپز است. او نیازی ندارد زل بزند تا آب یک قابلمه جوش بیاید (Block شدن)؛ بلکه زیر آن را روشن می‌کند (await) و فوراً سراغ خرد کردن پیازِ غذایی دیگر می‌رود! هر زمان که آب جوش آمد، زنگی به صدا در می‌آید و حلقه رویداد متوجه می‌شود که باید ادامه‌ی کار آن قابلمه را پی بگیرد.

یادداشت

معماری ناهمگام (asyncio) ذاتاً برای حل مشکلات گلوگاه‌های ورودی/خروجی (I/O-Bound) مثل درخواست‌های هزاران کلاینت همزمان در یک سرور شبکه طراحی شده است. اگر برنامه شما درگیر پردازش‌های فوق‌سنگینِ محاسباتی و جبری (CPU-Bound) است، معماریِ ناهمگام کمکی نمی‌کند، زیرا پردازنده واقعاً درگیر است و راهکارهای Multiprocessing نیاز خواهد بود.

async defکلمه کلیدی برای تبدیل یک تابع معمولی به یک "کوروتین" (Coroutine). فراخوانی این توابع به تنهایی هیچ چیزی را اجرا نمی‌کند، بلکه تنها یک شیء زمان‌بندی‌شده خلق می‌کند.
awaitدستوری الزامی پیش از اجرای کوروتین‌ها؛ اجرای کد در همان خط متوقف می‌شود تا نتیجه حاضر شود، اما هم‌زمان نبضِ کنترل به Event Loop برمی‌گردد تا باقیِ سیستم آزاد باشد.
asyncio.run()موتور استارتِ پایتون! این تابع وظیفه‌ی راه‌اندازی، نظارت و بستنِ نهایی حلقه رویداد (Event Loop) را در ریشه برنامه بر عهده دارد.
asyncio.sleep()نمادِ غیربرخوردکننده‌ی (Non-blocking) برای توقف زمان. کاملاً جایگزینِ time.sleep است که باعث می‌شود کل فرآیندهای برنامه برای لحظاتی به استراحت نروند.
نمونه‌ی آناتومیِ پایه
import asyncio

async def say_hello():
    print("سلام...")
    # برنامه‌های دیگر در این یک ثانیه متوقف نخواهند شد
    await asyncio.sleep(1)
    print("...پایتون!")

# نقطه شروع و ورود به قلمرو Async
asyncio.run(say_hello())
هشدار

دستور await در پایتون، تنها و تنها درون توابعی که با async def نشانه گذاری شده‌اند قابل استفاده است. همچنین هرگز نباید در توابع Async از دستوراتِ سنتیِ مسدودکننده مانند time.sleep() یا requests.get() استفاده کنید؛ زیرا پردازشِ سرور قفل شده و معماریِ ناهمگام را تبدیل به فاجعه خواهد کرد.

هنوز اجرا نشده

دکمه‌ی «اجرا» را بزن تا نتیجه را اینجا ببینی.

خروجی مورد انتظار

🚀 درخواستِ همزمانِ مجموعه‌ای از داده‌ها...
📥 [تسک 1] شروع اعتبارسنجی شبکه...
📥 [تسک 2] شروع اعتبارسنجی شبکه...
📥 [تسک 3] شروع اعتبارسنجی شبکه...
✅ [تسک 2] محموله دریافت شد (پس از 1.0 ثانیه).
✅ [تسک 3] محموله دریافت شد (پس از 1.5 ثانیه).
✅ [تسک 1] محموله دریافت شد (پس از 2.0 ثانیه).

📊 خروجی پایانی: ['Data_Pack_#1', 'Data_Pack_#2', 'Data_Pack_#3']
⏱ زمان کل: 2.00 ثانیه!
اگر هم‌روندی نداشتیم، این دانلود حداقل 4.5 ثانیه طول می‌کشید!