در پایتون، یک coroutine نوع خاصی از تابع است که میتواند اجرای خود را به صورت موقت متوقف کند و سپس از همان نقطه ادامه دهد. این امکان به برنامهنویسان اجازه میدهد که کدهای غیرهمزمان (asynchronous) بنویسند، که میتوانند به جای مسدود کردن کل برنامه برای انجام یک کار، به صورت موازی با سایر کارها اجرا شوند.
تعریف یک Coroutine
یک coroutine با استفاده از کلمات کلیدی async
و await
تعریف میشود. برای تبدیل یک تابع به coroutine، از کلمه کلیدی async
قبل از تعریف تابع استفاده میکنیم. برای متوقف کردن اجرای coroutine تا زمانی که نتیجه یک عملیات غیرهمزمان آماده شود، از await
استفاده میکنیم.
برای شروع، یک تابع ساده مینویسیم که از time.sleep
برای ایجاد تأخیر استفاده میکند:
import time
def sync_sleep():
print("Start sleeping...")
time.sleep(2)
print("Done sleeping!")
این تابع به صورت همزمان (synchronous) اجرا میشود و وقتی که time.sleep(2)
فراخوانی میشود، برنامه به مدت 2 ثانیه مسدود میشود. حالا میخواهیم این تابع را به یک تابع غیرهمزمان (asynchronous) تبدیل کنیم.
مرحله 1: تعریف تابع غیرهمزمان
ابتدا، تابع را به یک coroutine تبدیل میکنیم. برای این کار از کلمات کلیدی async
و await
استفاده میکنیم.
import asyncio
async def async_sleep():
print("Start sleeping...")
await asyncio.sleep(2)
print("Done sleeping!")
در اینجا، async def
نشاندهنده این است که async_sleep
یک coroutine است. await asyncio.sleep(2)
به جای time.sleep(2)
استفاده میشود تا برنامه به صورت غیرهمزمان به مدت 2 ثانیه متوقف شود.
مرحله 2: بررسی نوع تابع
برای نشان دادن اینکه این تابع یک coroutine است که هنوز اجرا نشده است، میتوانیم آن را فراخوانی کرده و نوع آن را چاپ کنیم:
<coroutine object async_sleep at 0x...>
مرحله 3: اجرای coroutine در رویداد لوپ
asyncio.run در پایتون برای سادهسازی اجرای برنامههای غیرهمزمان ایجاد شده است. این تابع با راهاندازی و مدیریت خودکار رویداد لوپ، اجرای coroutine اصلی، و سپس بستن و پاکسازی صحیح رویداد لوپ پس از اتمام، به کاهش پیچیدگی و احتمال بروز خطاهای مدیریتی کمک میکند. به طور خلاصه، `asyncio.run` اجرای برنامههای غیرهمزمان را راحتتر، ایمنتر و خواناتر میکند، به خصوص در اسکریپتهای ساده و تستها. برای اجرای یک coroutine، باید از رویداد لوپ asyncio
استفاده کنیم. برای این کار از تابع asyncio.run
استفاده میکنیم:
asyncio.run(async_sleep())
این کد رویداد لوپ را اجرا میکند و coroutine async_sleep
را تا زمانی که تکمیل شود اجرا میکند.
کد کامل و توضیح هر بخش
حال کل کد را به همراه توضیحات مرحله به مرحله بررسی میکنیم:
import asyncio
# 1. تعریف تابع غیرهمزمان
async def async_sleep():
print("Start sleeping...")
await asyncio.sleep(2) # 2. استفاده از await برای انتظار غیرهمزمان
print("Done sleeping!")
# 3. بررسی نوع coroutine
coro = async_sleep()
print(coro) # خروجی: <coroutine object async_sleep at 0x...>
# 4. اجرای coroutine در رویداد لوپ
asyncio.run(coro) # استفاده از asyncio.run برای اجرای coroutine
توضیحات
تعریف تابع غیرهمزمان:
async def async_sleep()
: این خط نشان میدهد کهasync_sleep
یک تابع غیرهمزمان (coroutine) است.await asyncio.sleep(2)
: این خط برنامه را به صورت غیرهمزمان به مدت 2 ثانیه متوقف میکند بدون اینکه کل برنامه مسدود شود.
بررسی نوع coroutine:
coro = async_sleep()
: این خط coroutine را ایجاد میکند اما آن را اجرا نمیکند.print(coro)
: این خط نشان میدهد کهcoro
یک شیء coroutine است که هنوز اجرا نشده است.
اجرای coroutine در رویداد لوپ:
asyncio.run(coro)
: این خط رویداد لوپ را اجرا میکند و coroutinecoro
را تا زمانی که تکمیل شود اجرا میکند.
این مراحل نشان میدهد که چگونه یک تابع همزمان با استفاده از time.sleep
به یک تابع غیرهمزمان با استفاده از asyncio.sleep
تبدیل میشود و چگونه این تابع غیرهمزمان اجرا میشود.