私は最近、単純なプロデューサー/コンシューマー パターンを使用するプログラムを作成しました。最初は、threading.Lock の不適切な使用に関連するバグがありましたが、最終的に修正しました。しかし、生産者/消費者パターンをロックレスで実装することは可能かどうか考えさせられました。
私の場合の要件は単純でした:
- 1 つのプロデューサー スレッド。
- 1 つのコンシューマ スレッド。
- キューには 1 つのアイテムしか入れられません。
- プロデューサーは、現在のアイテムが消費される前に次のアイテムを生成できます。したがって、現在のアイテムは失われますが、それで問題ありません。
- 消費者は、次のアイテムが生成される前に現在のアイテムを消費できます。したがって、現在のアイテムは 2 回 (またはそれ以上) 消費されますが、それは問題ありません。
だから私はこれを書いた:
QUEUE_ITEM = None
# this is executed in one threading.Thread object
def producer():
global QUEUE_ITEM
while True:
i = produce_item()
QUEUE_ITEM = i
# this is executed in another threading.Thread object
def consumer():
global QUEUE_ITEM
while True:
i = QUEUE_ITEM
consume_item(i)
私の質問は: このコードはスレッドセーフですか?
即時コメント: このコードは実際にはロックレスではありません - 私は CPython を使用しており、GIL を持っています。
コードを少しテストしたところ、うまくいくようです。これは、GIL のためにアトミックな LOAD および STORE 操作に変換されます。del x
しかし、x がメソッドを実装する場合、操作はアトミックではないことも知ってい__del__
ます。したがって、アイテムに__del__
メソッドがあり、厄介なスケジューリングが発生した場合、問題が発生する可能性があります。か否か?
もう 1 つの質問は、上記のコードを正常に動作させるには、どのような制限 (たとえば、生産されるアイテムの種類) を課す必要があるかということです。
私の質問は、CPython と GIL の癖を利用してロックレス (つまり、threading.Lock のようなロックをコードで明示的に使用しない) ソリューションを考え出す理論的な可能性についてのみです。