別の質問でのいくつかの議論は、マルチスレッドPythonプログラムでロックが必要な場合をよりよく理解するように私を促しました。
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()
上記のテストを失敗することなく実行しました(100x 100kマルチスレッド追加)。誰かがそれを失敗させることができますか?スレッドによるアトミック、インクリメンタル、変更を介して誤動作させることができる別のクラスのオブジェクトはありますか?
これらの暗黙の「アトミック」セマンティクスは、Pythonの他の操作に適用されますか?これはGILに直接関係していますか?