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

Please login to bookmark Close

تصور کنید گه پردازش هم‌زمان می‌خواهند از یک سرور دانلود فایل بگیرند، اما سرور فقط تحمل دو اتصال هم‌زمان را دارد؛ اگر همه با هم هجوم ببرند، یا خطا می‌گیرید یا سرعت به‌شدت افت می‌کند. اینجا دقیقاً جایی است که Semaphore در multiprocessing به کار می‌آید: یک شمارنده‌ی مشترک که می‌گوید «حداکثر N پردازش با هم اجازه‌ی ورود دارند، بقیه صف بکشند». اگر با نسخه‌ی threading کار کرده باشید، مفهوم دقیقاً همان است؛ فقط این‌بار به‌جای ترد، پردازش داریم.

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

ساخت یک Semaphore در multiprocessing

ساختنش یک خط است؛ عددی که می‌دهید همان سقف دسترسی هم‌زمان است:

sem = multiprocessing.Semaphore(2)  # at most 2 processes inside at once

یک نکته‌ی کلیدی که تازه‌کارها زیاد فراموشش می‌کنند: پردازش‌ها حافظه را مثل تردها به اشتراک نمی‌گذارند. پس نمی‌توانید sem را یک متغیر سراسری بگذارید و انتظار داشته باشید همه ببینندش. باید آن را صریحاً به‌عنوان آرگومان به تابع هدفِ هر پردازش پاس بدهید.

مثال واقعی: سقف دو دانلود هم‌زمان

پنج کارگر می‌سازیم، اما فقط دو تا در هر لحظه اجازه‌ی ورود به بخش دانلود را دارند. با عبارت with sem هم گرفتن و هم آزاد کردن مجوز خودکار انجام می‌شود:

import multiprocessing
import time

def download(sem, worker_id):
    with sem:  # acquire a slot; auto-release on exit
        print(f'worker-{worker_id}: downloading...')
        time.sleep(1)  # simulate network work
        print(f'worker-{worker_id}: done')

if __name__ == '__main__':  # required guard on Windows/macOS spawn
    sem = multiprocessing.Semaphore(2)
    workers = []
    for i in range(5):
        p = multiprocessing.Process(target=download, args=(sem, i))
        workers.append(p)
        p.start()
    for p in workers:
        p.join()  # wait for all to finish

اگر اجرا کنید می‌بینید که پیام‌های «downloading» دو‌تا‌دو‌تا ظاهر می‌شوند، نه هر پنج‌تا با هم. چرا؟ چون سومین پردازش پشت در می‌ماند تا یکی از آن دو جای اشغال‌شده آزاد شود. همین رفتار ساده، دقیقاً چیزی است که سرور محدود ما لازم داشت.

قرار دادن کل کد داخل if __name__ == '__main__': هم اختیاری نیست؛ روی ویندوز و macOS که پردازش‌ها با روش spawn ساخته می‌شوند، بدون این محافظ برنامه خودش را بی‌نهایت بار اجرا می‌کند.

BoundedSemaphore و یک تله‌ی رایج

یک اشتباه پرتکرار این است که جایی release() را دستی بیشتر از acquire() صدا بزنید؛ آن‌وقت شمارنده بی‌سروصدا از مقدار اولیه بالاتر می‌رود و ناگهان به‌جای دو، سه پردازش با هم وارد می‌شوند. دلیلش این است که Semaphore معمولی سقف را چک نمی‌کند. راه‌حل، استفاده از multiprocessing.BoundedSemaphore است که اگر release بیش از حد مجاز فراخوانی شود، بلافاصله استثنا پرتاب می‌کند و اشتباه را همان‌جا لو می‌دهد. به همین دلیل در کد جدی بهتر است همیشه نسخه‌ی Bounded را ترجیح بدهید (مثل نسخه‌ی threading آن).

کِی از Semaphore استفاده کنیم؟

اگر فقط می‌خواهید یک منبع را کاملاً انحصاری کنید (یک پردازش در یک زمان)، Lock کافی و سبک‌تر است. سراغ Semaphore بروید وقتی می‌خواهید «چند تا، اما نه بی‌نهایت» را اجازه بدهید: سقف اتصال به دیتابیس، تعداد دانلود هم‌زمان، یا تعداد کارگرهایی که به یک API نرخ‌محدود می‌زنند. مزیتش سادگی است؛ هزینه‌اش این است که خودش هیچ عدالتی تضمین نمی‌کند و ترتیب دقیق ورود پردازش‌ها قطعی نیست.

جمع‌بندی

  • Semaphore(N) تعداد پردازش‌های هم‌زمان در بخش حساس را به N محدود می‌کند.
  • چون حافظه مشترک نیست، شیء را حتماً به‌عنوان آرگومان به پردازش‌ها پاس بدهید.
  • کل کد اجرا‌کننده باید زیر if __name__ == '__main__': باشد.
  • برای امنیت بیشتر و گرفتن باگ‌های release اضافی، از BoundedSemaphore استفاده کنید.
Please login to bookmark Close
پیشرفت شما در «دوره آموزش کانکارنسی در پایتون» (79%)
نظرات

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

79%
پیشرفت

سرفصل دوره

فهرست مطالب

سرفصل دوره

تمرین

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

پاسخ تمرین ها

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

اشتراک گذاری

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

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

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

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

تنظیمات

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