24

私はPythonでスレッド化をまったく行ったことがなく、この質問を完全に見知らぬ人として尋ねました。

defaultdictスレッドセーフかどうか疑問に思っています。説明させてください:

私は持っている

d = defaultdict(list)

これにより、デフォルトで欠落しているキーのリストが作成されます。複数のスレッドが同時にこれを開始したとしましょう:

d['key'].append('value')

最後に、私はで終わるはずです['value', 'value']。ただし、defaultdictがスレッドセーフでない場合、チェック後および の前 にスレッド 1がスレッド 2に譲ると、インターリーブが発生し、他のスレッドがリストを作成して追加する可能性があります。if 'key' in dictd['key'] = default_factory()d['key']'value'

その後、スレッド 1d['key'] = default_factory()が再び実行されると、既存のリストと値が破棄されてスレッド 1が続行され、最終的に['key'].

defaultdictの CPython ソース コードを調べました。ただし、ロックやミューテックスは見つかりませんでした。文書化されている限り、スレッドセーフではないと思います。

昨夜の IRC で、Python には GIL があり、概念的にはスレッドセーフであると述べた人もいました。Python ではスレッド化を行うべきではないと言う人もいます。私はかなり混乱しています。アイデア?

4

1 に答える 1

31

この特定のケースでは、スレッドセーフです。

Python がいつスレッドを切り替えるかを理解することが重要である理由を知るために。CPython では、Python バイトコード ステップ間のスレッド間の切り替えのみが許可されます。ここで GIL の出番です。N バイトのコード命令ごとにロックが解除され、スレッドの切り替えを行うことができます。

このコードは、辞書で呼び出されるメソッドをトリガーするd['key']1 つのバイトコード ( ) によって処理されます。BINARY_SUBSCR.__getitem__()

defaultdictデフォルト値 factory として構成さlistれ、文字列値をキーとして使用するAは、dict.__getitem__()メソッドを完全に C で処理、GIL は決してロック解除されないため、dict[key]ルックアップはスレッドセーフになります。

そこの資格に注意してください。Python コードを使用する別のデフォルト値ファクトリ (たとえば) を持つdefaultdictインスタンスを作成すると、C コードが Python コードにコールバックし、バイトコードの実行中に GIL が再び解放されることを意味するため、すべての賭けは無効になります。関数。同じことがキーにも当てはまります。またはPython コードで実装するオブジェクトを使用すると、そこでスレッド切り替えが発生する可能性があります。次に、ファクトリが GIL を明示的に解放する C コードで記述されている場合、スレッドの切り替えが発生する可能性があり、スレッドの安全性は窓の外にあります。lambda: [1, 2, 3]lambda__hash____eq__

于 2013-07-16T16:54:06.313 に答える