Некоторое обсуждение в другом вопросе побудило меня лучше понять случаи, когда требуется блокировка в многопоточных программах Python.
Per эта статья для потоковой передачи в Python, у меня есть несколько твердых, тестируемых примеров ошибок, которые могут возникнуть, когда несколько потоков обращаются к общему состоянию. Пример состояния гонки, представленный на этой странице, включает в себя гонки между чтением потоков и манипулирование общей переменной, хранящейся в словаре. Я думаю, что случай для гонки здесь очень очевиден, и, к счастью, он в высшей степени проверен.
Однако я не смог вызвать условие гонки с помощью атомных операций, таких как добавление списка или приращение переменной. Этот тест полностью пытается продемонстрировать такую гонку:
from threading import Thread, Lock
import operator
def contains_all_ints(l, n):
l.sort()
for i in xrange(0, n):
if l[i] != i:
return False
return True
def test(ntests):
results = []
threads = []
def lockless_append(i):
results.append(i)
for i in xrange(0, ntests):
threads.append(Thread(target=lockless_append, args=(i,)))
threads[i].start()
for i in xrange(0, ntests):
threads[i].join()
if len(results) != ntests or not contains_all_ints(results, ntests):
return False
else:
return True
for i in range(0,100):
if test(100000):
print "OK", i
else:
print "appending to a list without locks *is* unsafe"
exit()
Я выполнил тест выше без сбоев (100x100k многопоточно добавляет). Может ли кто-нибудь заставить его потерпеть неудачу? Есть ли другой класс объекта, который может быть сделан для неправильной работы через атомарную, инкрементальную, модификацию по потокам?
Используются ли эти неявно "атомарные" семантики для других операций в Python? Связано ли это с GIL?