Вопрос проверяет понимание механизмов синхронизации доступа к разделяемым данным в многопоточных приложениях.
Когда несколько потоков одновременно обращаются к общим данным, может возникнуть состояние гонки (race condition). Чтобы этого избежать, используют механизмы синхронизации. Два основных подхода — блокировки (Lock, Mutex) и атомарные операции.
Блокировка гарантирует, что только один поток может выполнять защищённый участок кода в данный момент. Другие потоки ожидают освобождения блокировки. Это простой и надёжный способ, но может привести к снижению производительности из-за ожидания.
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(1000):
with lock:
counter += 1
threads = [threading.Thread(target=increment) for _ in range(10)]
for t in threads: t.start()
for t in threads: t.join()
print(counter) # 10000Атомарные операции выполняются как единое неделимое действие. Они быстрее блокировок, так как не требуют переключения контекста. Подходят для простых операций, таких как инкремент или сравнение с обменом (CAS).
import threading
import atomic
counter = atomic.AtomicInteger(0)
def increment():
for _ in range(1000):
counter.inc()
threads = [threading.Thread(target=increment) for _ in range(10)]
for t in threads: t.start()
for t in threads: t.join()
print(counter.get()) # 10000Используйте атомарные операции для простых счётчиков и флагов, а блокировки — для сложных критических секций, где требуется выполнение нескольких операций как единого целого.