۴ کیو· سختپیشرفتهPYTHON۴ ثانیه · ۲۵۶ مگابایت
مثجاوا (Synchronized Decorator)
در این تمرین، از شما خواسته میشود یک دکوراتور بنویسید که عملکردی مشابه کلیدواژهی synchronized در زبان جاوا داشته باشد.
این دکوراتور باید به گونهای پیادهسازی شود که وقتی بر روی یک تابع قرار میگیرد، تضمین کند که در هر لحظه، تنها یک ترد اجازهی اجرای آن تابع را دارد.
- اگر چندین ترد بهصورت همزمان تلاش کنند تا تابع دکورهشده را فراخوانی کنند، سایر تردها تا زمان اتمام اجرای تابع توسط ترد جاری، در حالت انتظار باقی خواهند ماند.
- اجرای تردهای منتظر بهصورت ترتیبی (بر اساس زمان ورود به صف انتظار) انجام خواهد شد.
- برای پیادهسازی این همگامسازی، شما باید از شیء
Lockاستفاده کنید.
⚠️ نکات مهم
- دکوراتور شما باید به گونهای نوشته شود که بتواند بر روی هر تابعی، صرف نظر از تعداد و نوع آرگومانهای ورودی و مقادیر خروجی آن، اعمال شود و عملکرد صحیح داشته باشد.
- سازوکار اصلی همگامسازی در دکوراتور شما حتماً باید با استفاده از یک شیء
Lockمدیریت شود.
🎯 مثال
python
from threading import Thread, Lock
def synchronized(func):
...
a = 0
@synchronized
def f():
global a
for i in range(300000):
a += 1
t = Thread(target=f)
s = Thread(target=f)
print("Starting threads...")
t.start()
s.start()
t.join()
s.join()
print("Threads finished.")
print(f'{a = }')
خروجی:
text
Starting threads...
Threads finished.
a = 600000
- دو ترد (
tوs) ایجاد شدهاند که هر دو تابعfرا اجرا میکنند.- تابع
fیک متغیر سراسری به نامaرا ۳۰۰۰۰۰ بار افزایش میدهد.- با استفاده از دکوراتور
@synchronizedکه شما پیادهسازی میکنید، اجرای تابعfهمگامسازی میشود.- مقدار نهایی متغیر
aدقیقاً برابر با حاصل جمع افزایشهای هر دو ترد (۶۰۰۰۰۰) خواهد بود.
💡 راهنمایی
ساختار کلی دکوراتور @synchronized به این شکل است:
python
def synchronized(func):
lock = Lock()
def wrapper(*args, **kwargs):
with lock:
return func(*args, **kwargs)
return wrapper
- دکوراتور
@synchronizedیکLockایجاد میکند که بین تمام فراخوانیهای تابع مشترک است.- تابع
wrapperبا استفاده ازwithقفل را میگیرد و سپس تابع اصلی را اجرا میکند.- استفاده از
withتضمین میکند که قفل پس از اجرای تابع (حتی در صورت بروز خطا) آزاد شود.- استفاده از
*argsو**kwargsباعث میشود دکوراتور بر روی هر تابعی با هر تعداد آرگومان کار کند.- مقدار بازگشتی تابع اصلی با
returnبرگردانده میشود.
- در این تمرین، نیازی به دریافت ورودی از کاربر یا چاپ خروجی در کنسول ندارید.
- شما فقط باید دکوراتور
@synchronizedرا پیادهسازی کنید.- دکوراتور شما باید با استفاده از
Lockهمگامسازی را انجام دهد.- دکوراتور باید بر روی هر نوع تابعی (با هر تعداد آرگومان) کار کند.
- نیازی به فراخوانی دکوراتور در کد ارسالی نیست. سیستم بهطور خودکار آن را تست خواهد کرد.
✅ این تمرین را در ویرایشگر خود پیادهسازی کنید. به یاد داشته باشید که دکوراتور
@synchronizedباید با استفاده ازLockهمگامسازی را انجام دهد.
نمونهها
ورودی نمونه ۱
import time
from threading import Thread
counter = {"n": 0}
@synchronized
def bump():
for _ in range(200):
value = counter["n"]
time.sleep(0)
counter["n"] = value + 1
threads = [Thread(target=bump) for _ in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
counter["n"]خروجی نمونه ۱
800
ورودی نمونه ۲
import time
from threading import Thread
inside = []
overlaps = []
@synchronized
def work():
inside.append(1)
if len(inside) > 1:
overlaps.append(True)
time.sleep(0.01)
inside.pop()
threads = [Thread(target=work) for _ in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()
overlapsخروجی نمونه ۲
[]
ورودی نمونه ۳
@synchronized
def add(a, b=0):
return a + b
add(2, 3)
add(5, b=7)خروجی نمونه ۳
5 12
ورودی نمونه ۴
@synchronized
def maybe(fail):
if fail:
raise ValueError("boom")
return "ok"
try:
maybe(True)
except ValueError as error:
print(error)
maybe(False)خروجی نمونه ۴
boom 'ok'
برای نوشتن پاسخ و دریافت امتیاز، ابتدا وارد حساب شوید.
ورود