Files
2026-10-07 13:06:47 +05:00

69 lines
2.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""Демо: гонка данных — потерянные обновления счётчика.
Запуск из корня курса:
python lab05_sync/examples/01_race_demo.py
counter += 1 — три операции (чтение, инкремент, запись). Два потока читают
одно значение, оба пишут — одно увеличение теряется. Lock устраняет гонку.
"""
import os
import sys
import threading
import time
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
N_THREADS = 8
N_INCR = 100_000
def worker_unsafe(counter):
for _ in range(N_INCR):
value = counter[0] # ЧТЕНИЕ
time.sleep(0) # усиливает переключения: GIL уступается
counter[0] = value + 1 # ЗАПИСЬ (могла потеряться)
def worker_safe(counter, lock):
for _ in range(N_INCR):
with lock: # критическая секция
value = counter[0]
counter[0] = value + 1
def main():
expected = N_THREADS * N_INCR
counter = [0]
threads = [threading.Thread(target=worker_unsafe, args=(counter,))
for _ in range(N_THREADS)]
t0 = time.perf_counter()
for t in threads:
t.start()
for t in threads:
t.join()
unsafe_time = time.perf_counter() - t0
print(f"без синхронизации: {counter[0]:>10,} из {expected:,} "
f"(потеряно {expected - counter[0]:,}) за {unsafe_time:.2f} c")
counter = [0]
lock = threading.Lock()
threads = [threading.Thread(target=worker_safe, args=(counter, lock))
for _ in range(N_THREADS)]
t0 = time.perf_counter()
for t in threads:
t.start()
for t in threads:
t.join()
safe_time = time.perf_counter() - t0
print(f"с Lock: {counter[0]:>10,} из {expected:,} "
f"(идеально) за {safe_time:.2f} c")
print(f"\nРазница времени: {(safe_time - unsafe_time) / unsafe_time * 100:+.0f}%")
print("(Lock может даже ускорить: без него потоки чаще конфликтуют)")
print("Запустите ещё раз — потерянные обновления будут другими:")
print("гонка недетерминирована, этим она и опасна.")
if __name__ == "__main__":
main()