اجراکننده‌ها

کد منبع: Lib/asyncio/runners.py

این بخش، سازوکارهای اولیه سطح بالای asyncio برای اجرای کد asyncio را به‌طور خلاصه شرح می‌دهد.

آن‌ها بر پایه یک حلقه رویداد ساخته شده‌اند تا استفاده از کد ناهمگام را برای سناریوهای رایج و گسترده ساده‌تر کنند.

اجرای یک برنامه asyncio

asyncio.run(coro, *, debug=None, loop_factory=None)

coro را در یک حلقه رویداد asyncio اجرا می‌کند و نتیجه را برمی‌گرداند.

آرگومان می‌تواند هر شیء awaitable باشد.

این تابع، awaitable را اجرا می‌کند و مدیریت حلقه رویداد asyncio، نهایی‌سازی تولیدگرهای ناهمگام و بستن اجراکننده (executor) را بر عهده می‌گیرد.

هنگامی که یک حلقه رویداد asyncio دیگر در همان نخ در حال اجرا است، نمی‌توانید این تابع را فراخوانی کنید.

اگر debug برابر True باشد، حلقه رویداد در حالت اشکال‌زدایی اجرا می‌شود. False حالت اشکال‌زدایی را به‌صراحت غیرفعال می‌کند. None برای رعایت تنظیمات سراسری حالت اشکال‌زدایی استفاده می‌شود.

اگر loop_factory None نباشد، از آن برای ایجاد یک حلقه رویداد جدید استفاده می‌شود؛ در غیر این صورت از asyncio.new_event_loop() استفاده می‌شود. حلقه در پایان بسته می‌شود. این تابع باید به عنوان نقطه ورود اصلی برنامه‌های asyncio استفاده شود و بهتر است فقط یک بار فراخوانی شود. توصیه می‌شود به جای سیاست‌ها (policies)، برای پیکربندی حلقه رویداد از loop_factory استفاده کنید. ارسال asyncio.EventLoop امکان اجرای asyncio بدون سیستم سیاست (policy system) را فراهم می‌کند.

به اجراکننده (executor) مهلتی به مدت ۵ دقیقه برای خاموش شدن داده می‌شود. اگر اجراکننده در آن مدت کار خود را به پایان نرسانده باشد، هشداری نشان داده می‌شود و اجراکننده بسته می‌شود.

مثال:

async def main():
    await asyncio.sleep(1)
    print('hello')

asyncio.run(main())

اضافه شده در نسخه‌ی 3.7.

تغییر یافته در نسخه‌ی 3.9: برای استفاده از loop.shutdown_default_executor() به‌روزرسانی شد.

تغییر یافته در نسخه‌ی 3.10: debug به‌طور پیش‌فرض None است تا تنظیمات سراسری حالت اشکال‌زدایی را رعایت کند.

تغییر یافته در نسخه‌ی 3.12: پارامتر loop_factory افزوده شد.

تغییر یافته در نسخه‌ی 3.14: coro می‌تواند هر شیء قابل await (awaitable) باشد.

توجه

سیستم سیاست asyncio منسوخ شده است و در Python 3.16 حذف خواهد شد؛ از آن پس، برای پیکربندی حلقه رویداد به یک loop_factory صریح نیاز است.

مدیر زمینه‌ی Runner

class asyncio.Runner(*, debug=None, loop_factory=None)

مدیر زمینه‌ای که فراخوانی‌های چندگانه تابع ناهمگام را در همان زمینه ساده‌تر می‌کند.

گاهی اوقات چندین تابع ناهمگام سطح بالا باید در یک حلقه رویداد و contextvars.Context مشترک فراخوانی شوند.

اگر debug برابر True باشد، حلقه رویداد در حالت اشکال‌زدایی اجرا می‌شود. False حالت اشکال‌زدایی را به‌صراحت غیرفعال می‌کند. None برای رعایت تنظیمات سراسری حالت اشکال‌زدایی استفاده می‌شود.

loop_factory می‌تواند برای بازنویسی ایجاد حلقه استفاده شود. مسئولیت تنظیم حلقه‌ی ایجادشده به‌عنوان حلقه‌ی جاری بر عهده‌ی loop_factory است. به‌طور پیش‌فرض، اگر loop_factory برابر None باشد، از asyncio.new_event_loop() استفاده می‌شود و با asyncio.set_event_loop() به‌عنوان حلقه‌ی رویداد جاری تنظیم می‌شود.

اساساً، می‌توان مثال asyncio.run() را با استفاده از اجراکننده (runner) بازنویسی کرد:

async def main():
    await asyncio.sleep(1)
    print('hello')

with asyncio.Runner() as runner:
    runner.run(main())

اضافه شده در نسخه‌ی 3.11.

run(coro, *, context=None)

coro را در حلقه رویداد تعبیه‌شده اجرا کنید.

آرگومان می‌تواند هر شیء awaitable باشد.

اگر آرگومان یک هم‌روال باشد، در یک Task پیچیده می‌شود.

یک آرگومان اختیاری فقط کلیدواژه‌ای context به شما امکان می‌دهد یک contextvars.Context سفارشی برای کدی که در آن اجرا می‌شود مشخص کنید. اگر context برابر None باشد، از زمینه پیش‌فرض اجراکننده استفاده می‌شود.

نتیجه‌ی awaitable را برمی‌گرداند یا یک استثنا را پرتاب می‌کند.

هنگامی که یک حلقه رویداد asyncio دیگر در همان نخ در حال اجرا است، نمی‌توانید این تابع را فراخوانی کنید.

تغییر یافته در نسخه‌ی 3.14: coro می‌تواند هر شیء قابل await (awaitable) باشد.

close()

اجراکننده را ببندید.

نهایی‌سازی تولیدگرهای ناهمگام، خاموش کردن اجراکننده‌ی پیش‌فرض، بستن حلقه‌ی رویداد و آزادسازی contextvars.Context تعبیه‌شده.

get_loop()

حلقه‌ی رویداد مرتبط با نمونه‌ی اجراکننده را بازمی‌گرداند.

توجه

Runner از راهبرد مقداردهی اولیه تنبل استفاده می‌کند، سازنده‌ی آن ساختارهای زیربنایی سطح پایین را مقداردهی اولیه نمی‌کند.

حلقه و زمینه تعبیه‌شده در هنگام ورود به بدنه‌ی with یا نخستین فراخوانی run() یا get_loop() ایجاد می‌شوند.

مدیریت وقفه صفحه‌کلید

اضافه شده در نسخه‌ی 3.11.

هنگامی که signal.SIGINT با Ctrl-C پرتاب می‌شود، به‌طور پیش‌فرض استثنای KeyboardInterrupt در نخ اصلی پرتاب می‌شود. اما این مورد با asyncio کار نمی‌کند، زیرا می‌تواند اجزای داخلی asyncio را مختل کند و باعث شود برنامه هنگام خروج معلق بماند.

برای کاهش این مشکل، asyncio، signal.SIGINT را به‌صورت زیر مدیریت می‌کند:

  1. asyncio.Runner.run() پیش از اجرای هر کد کاربر، یک هندلر سفارشی برای signal.SIGINT نصب می‌کند و هنگام خروج از تابع، آن را حذف می‌کند.

  2. Runner برای اجرای هم‌روالِ داده‌شده، وظیفه‌ی اصلیرا ایجاد می‌کند.

  3. هنگامی که signal.SIGINT با Ctrl-C پرتاب می‌شود، هندلر سیگنال سفارشی وظیفه اصلی را با فراخوانی asyncio.Task.cancel() که asyncio.CancelledError را درون وظیفه اصلی پرتاب می‌کند، لغو می‌کند. این امر باعث می‌شود پشته پایتون باز شود؛ می‌توان از بلوک‌های try/except و try/finally برای پاک‌سازی منابع استفاده کرد. پس از لغو شدن وظیفه اصلی، asyncio.Runner.run() KeyboardInterrupt را پرتاب می‌کند.

  4. ممکن است کاربر یک حلقه فشرده بنویسد که توسط asyncio.Task.cancel() قابل وقفه نباشد؛ در این صورت، دومین Ctrl-C پس از آن، بلافاصله KeyboardInterrupt را بدون لغو وظیفه اصلی پرتاب می‌کند.