پاسخ تمرین ۱
این همان Race Condition است: چند پردازش همزمان مقدار منبع مشترک را میخوانند و دوباره مینویسند، و تعدادی از این بهروزرسانیها گم میشود (چون value += 1 اتمیک نیست).
پاسخ تمرین ۲
Lock دو متد acquire (بستن قفل) و release (بازکردن قفل) را میدهد.
پاسخ تمرین ۳
باید فقط یک پردازش بین acquire و release اجازهی اجرای کد تغییردهنده را داشته باشد؛ بقیه باید منتظر بمانند تا قفل آزاد شود.
پاسخ تمرین ۴
با with lock حتی اگر داخل بلوک خطایی رخ دهد، قفل بهصورت خودکار آزاد میشود و لازم نیست خودمان بهیاد داشته باشیم release را صدا کنیم.
پاسخ تمرین ۵
import multiprocessing
lock = multiprocessing.Lock()
shared_counter = multiprocessing.Value('i', 0)
def increment_counter(shared_counter, lock):
with lock:
for _ in range(100000):
shared_counter.value += 1
if __name__ == '__main__':
processes = [multiprocessing.Process(target=increment_counter, args=(shared_counter, lock))
for _ in range(5)]
for p in processes: p.start()
for p in processes: p.join()
print("Final value:", shared_counter.value) # 500000پاسخ تمرین ۶
import multiprocessing
shared_counter = multiprocessing.Value('i', 0)
def increment_counter(shared_counter):
with shared_counter.get_lock(): # Value's built-in lock
for _ in range(100000):
shared_counter.value += 1
if __name__ == '__main__':
processes = [multiprocessing.Process(target=increment_counter, args=(shared_counter,))
for _ in range(5)]
for p in processes: p.start()
for p in processes: p.join()
print("Final value:", shared_counter.value) # 500000پاسخ تمرین ۷
import multiprocessing
def worker(chunk, success_count, lock):
local = sum(1 for x in chunk if x % 2 == 0) # heavy work OUTSIDE the lock
with lock:
success_count.value += local # only the shared update is locked
if __name__ == '__main__':
lock = multiprocessing.Lock()
success_count = multiprocessing.Value('i', 0)
data = list(range(100))
chunks = [data[i::4] for i in range(4)]
procs = [multiprocessing.Process(target=worker, args=(c, success_count, lock)) for c in chunks]
for p in procs: p.start()
for p in procs: p.join()
print("total evens found:", success_count.value) # 50پاسخ تمرین ۸
قفلکردن کل حلقه، پردازهها را عملاً سریالی میکند؛ یعنی هر بار فقط یک پردازه کار میکند و مزیت موازیسازی از بین میرود. راه بهتر این است که کار سنگین را بیرون از قفل انجام دهید و فقط بخش کوچکی را که به منبع مشترک دست میزند (مثل جمعزدن نهایی) داخل قفل بگذارید.