پاسخ تمرینات کلاس Condition در ماژول threading

Please login to bookmark Close


پاسخ تمرین ۱

Condition برای هماهنگیِ «منتظرماندن تا وقوع یک شرط» بین تردها (الگوی تولیدکننده/مصرف‌کننده) استفاده می‌شود. نسبت به busy-waiting بهتر است چون ترد منتظر می‌خوابد و CPU مصرف نمی‌کند؛ فقط وقتی شرط برقرار شد با notify بیدار می‌شود.

پاسخ تمرین ۲

در حالت if، ترد فقط یک‌بار شرط را بررسی می‌کند و اگر بیدارشدنش به‌اشتباه (Spurious Wakeup) یا به‌خاطر نوتیفای ترد دیگری باشد، بدون اینکه شرط واقعی برقرار شده باشد ادامه می‌دهد — همان اشکال «گارسون سارق». while باعث می‌شود ترد بعد از هر بار بیدارشدن دوباره شرط را بررسی کند و فقط وقتی واقعاً برقرار است از حلقه خارج شود؛ در نتیجه هم Spurious Wakeup و هم از دست رفتن Notify برطرف می‌شود.

پاسخ تمرین ۳

notify() فقط یکی از تردهای منتظر را (به انتخاب سیستم) بیدار می‌کند، اما notify_all() همه را. وقتی فقط یک منبع برای مصرف آماده شده، notify() کافی است؛ اما اگر وضعیتِ مشترک تغییر کرده و چند ترد باید دوباره شرط را بررسی کنند، از notify_all() استفاده کنید تا هیچ تردی برای همیشه منتظر نماند.

پاسخ تمرین ۴

main_lock از داده‌های عمومی انبار محافظت می‌کند و item_condition مخصوص هماهنگ‌کردن تردهایی است که منتظر رسیدن یک کالای خاص‌اند. اگر فقط یک قفل مشترک به کار می‌رفت، تردی که روی Condition منتظر است باید همان قفل عمومی را هم نگه می‌داشت (چون wait فقط قفلِ خودِ Condition را آزاد می‌کند)؛ این می‌توانست به Deadlock منجر شود، چون تولیدکننده برای ثبت کالا به قفل عمومی نیاز دارد اما آن در دست مصرف‌کننده‌ی خوابیده مانده است.

پاسخ تمرین ۵

وقتی تردی در حالی که قفل Condition را در اختیار دارد یک تأخیر طولانی (با time.sleep) اجرا کند، همه‌ی تردهای منتظرِ همان قفل هم باید همان مدت صبر کنند، حتی اگر کاری برای انجام‌دادن نداشته باشند. این کار هم‌زمانی را به‌شدت کم می‌کند و مزیت چند ترد را از بین می‌برد. قاعده: فقط بخشی را که به منبع مشترک دست می‌زند داخل قفل بگذارید و کارهای سنگین را بیرون از آن انجام دهید.

پاسخ تمرین ۶

import threading
import time

condition = threading.Condition()
is_ready = False

def waiter():
    with condition:
        while not is_ready:
            condition.wait()
        print("[Waiter] order is ready, serving it!")

def chef():
    global is_ready
    time.sleep(1)
    with condition:
        is_ready = True
        print("[Chef] done! notifying...")
        condition.notify()

threading.Thread(target=waiter).start()
threading.Thread(target=chef).start()

پاسخ تمرین ۷

import threading
import time

condition = threading.Condition()
job_queue = []

def worker():
    while True:
        with condition:
            while not job_queue:
                condition.wait()
            job = job_queue.pop(0)
        if job is None:              # shutdown signal
            print("worker stopping")
            break
        print("processing", job)
        time.sleep(0.2)

def dispatcher(jobs):
    for j in jobs:
        with condition:
            job_queue.append(j)
            condition.notify()
        time.sleep(0.1)
    with condition:
        job_queue.append(None)       # tell the worker to stop
        condition.notify()

w = threading.Thread(target=worker)
d = threading.Thread(target=dispatcher, args=(['a', 'b', 'c'],))
w.start(); d.start()
w.join(); d.join()

راه‌حل جایگزین: در عمل معمولاً به‌جای پیاده‌سازی دستی از queue.Queue استفاده می‌شود که در پشت‌صحنه بر پایه‌ی Condition ساخته شده است.

پاسخ تمرین ۸

این متدها باید وقتی فراخوانی شوند که قفلِ Condition در دست ماست؛ یعنی داخل بلاک with condition: یا بین acquire() و release(). اگر بیرون از قفل صدا زده شوند، RuntimeError رخ می‌دهد.

Please login to bookmark Close
نظرات

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

فهرست مطالب

سرفصل دوره

تمرین

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

پاسخ تمرین ها

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

اشتراک گذاری

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

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

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

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

تنظیمات

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