Является ли список (list) в Python потокобезопасным?

Ответ

В Python список (list) не является потокобезопасным. Это означает, что если несколько потоков одновременно изменяют список (например, добавляют или удаляют элементы), это может привести к состоянию гонки (race condition), повреждению данных или неожиданному поведению. Это происходит потому, что операции со списком не являются атомарными.

Пример проблемы (состояние гонки):

import threading

shared_list = []

def add_items():
    for i in range(1000):
        shared_list.append(i)

threads = []
for _ in range(10):
    t = threading.Thread(target=add_items)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

# Ожидаемый размер: 10 * 1000 = 10000
# Фактический размер может быть меньше из-за состояний гонки
print(len(shared_list))

Решение для потокобезопасной работы:

  1. Использование threading.Lock: Это самый распространенный способ синхронизации доступа к общим ресурсам. Блокировка гарантирует, что только один поток может выполнять критическую секцию кода в любой момент времени.

    import threading
    
    lock = threading.Lock()
    shared_list = []
    
    def add_items_safe():
        for i in range(1000):
            with lock: # Захватываем блокировку перед изменением списка
                shared_list.append(i)
    
    threads = []
    for _ in range(10):
        t = threading.Thread(target=add_items_safe)
        threads.append(t)
        t.start()
    
    for t in threads:
        t.join()
    
    print(len(shared_list)) # Будет 10000
  2. Использование queue.Queue: Если требуется потокобезопасная структура данных с логикой FIFO (первым пришел — первым ушел), queue.Queue из модуля queue является отличным выбором, так как он изначально разработан для потокобезопасного обмена данными между потоками.

  3. Для межпроцессного взаимодействия: Для обмена данными между процессами (не потоками) можно использовать multiprocessing.Manager().list() или другие средства синхронизации из модуля multiprocessing.