آموزش ماژول asyncio – کلاس Semaphore

Please login to bookmark Close

مقدمه

فرض کنید قصد دارید چند درخواست شبکه را به‌صورت هم‌زمان ارسال کنید، اما سرور مقصد یا منابع سیستم شما اجازهٔ بیش از تعداد معینی اتصال هم‌زمان را نمی‌دهد. در چنین شرایطی، باید بتوانید تعداد Task‌هایی را که هم‌زمان در حال اجرا هستند محدود کنید. کلاس Semaphore در ماژول asyncio دقیقاً همین کار را انجام می‌دهد.

Semaphore چیست؟

Semaphore یک شمارندهٔ داخلی دارد که با یک مقدار اولیه ساخته می‌شود. هر بار که یک Task آن را acquire (تصاحب) می‌کند، این شمارنده یک واحد کم می‌شود، و هر بار که release (آزاد) می‌شود، یک واحد زیاد می‌شود. اگر شمارنده به صفر برسد، هر Task جدیدی که بخواهد آن را تصاحب کند، باید منتظر بماند تا یکی از Task‌های قبلی آن را آزاد کند.

import asyncio

async def main():
    semaphore = asyncio.Semaphore(2)
    print(f'مقدار اولیه: {semaphore._value}')

asyncio.run(main())

استفاده با async with

راحت‌ترین روش استفاده از Semaphore، به‌کار بردن آن به‌صورت یک Context Manager با async with است. در این حالت، در ابتدای بلوک acquire و در پایان بلوک release به‌صورت خودکار انجام می‌شود، حتی اگر داخل بلوک خطایی رخ دهد.

import asyncio

async def fetch_data(semaphore, name, delay):
    async with semaphore:
        print(f'{name}: شروع شد')
        await asyncio.sleep(delay)
        print(f'{name}: پایان یافت')

async def main():
    semaphore = asyncio.Semaphore(2)
    tasks = [
        asyncio.create_task(fetch_data(semaphore, f'Task {i}', 2))
        for i in range(5)
    ]
    await asyncio.gather(*tasks)

asyncio.run(main())

در این مثال، با اینکه ۵ Task ساخته شده، اما چون مقدار Semaphore برابر با ۲ است، در هر لحظه حداکثر ۲ Task به‌صورت هم‌زمان اجرا می‌شوند و بقیه منتظر می‌مانند تا یکی از آن دو، semaphore را آزاد کند.

به‌جای async with می‌توان از روش دستی هم استفاده کرد، اما در این حالت باید حتماً از try/finally استفاده کنید تا در صورت بروز خطا هم release فراموش نشود:

await semaphore.acquire()
try:
    pass
finally:
    semaphore.release()

تفاوت Semaphore و BoundedSemaphore

کلاس asyncio.BoundedSemaphore دقیقاً مثل Semaphore عمل می‌کند، با یک تفاوت: اگر تعداد release بیشتر از تعداد acquire باشد، خطای ValueError ایجاد می‌کند. این ویژگی برای پیدا کردن باگ‌هایی که در آن‌ها release به‌اشتباه چند بار صدا زده می‌شود بسیار مفید است.

جمع‌بندی

کلاس Semaphore ابزاری ساده و کاربردی برای محدود کردن تعداد Task‌های هم‌زمانِ فعال است؛ مثلاً برای کنترل تعداد درخواست‌های هم‌زمان به یک API یا پایگاه‌داده. در درس بعدی با کلاس Event در asyncio آشنا می‌شویم که به Task‌ها امکان می‌دهد منتظر یک رویداد مشخص بمانند.

Please login to bookmark Close
پیشرفت شما در «دوره آموزش کانکارنسی در پایتون» (59%)
نظرات

دیدگاهتان را بنویسید

59%
پیشرفت

سرفصل دوره

فهرست مطالب

سرفصل دوره

تمرین

این قسمت تمرین ندارد!

پاسخ تمرین ها

هنوز برای تمرین‌های این قسمت پاسخی ثبت نشده است!

اشتراک گذاری

چرا بهتره از فیلترشکن استفاده کنید؟

من همه ویدئو ها و پادکست های کُدباز رو توی یوتیوب و ساندکلود و پلتفرم هایی آپلود می‌کنم که اغلب فیلتر هستند.

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

توجه داشته باشید که برای خرید از فروشگاه بهتره فیلتر شکن رو خاموش کنید.

تنظیمات

انتخاب زبان
تغییر تم