web-dev-qa-db-ja.com

Pythonの辞書のスレッドセーフ

辞書を保持するクラスがあります

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

そして、OrderBook.addOrderメソッドを呼び出す4つのスレッド(レストランごとに1つ)を実行しています。各スレッドで実行される関数は次のとおりです。

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

これは安全ですか、それともaddOrderを呼び出す前にロックを使用する必要がありますか?

86
nmat

Pythonの組み込み構造は、単一の操作に対してスレッドセーフですが、ステートメントが実際に複数の操作になる場所を確認するのが難しい場合があります。

コードは安全でなければなりません。留意してください:ここのロックはオーバーヘッドをほとんど追加しないので、安心できます。

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm に詳細があります。

78
Ned Batchelder

はい、組み込み型は本質的にスレッドセーフです: http://docs.python.org/glossary.html#term-global-interpreter-lock

これにより、同時アクセスに対して暗黙的に安全なオブジェクトモデル(dictなどの重要な組み込み型を含む)を作成することにより、CPythonの実装が簡素化されます。

28
user626998

Googleのスタイルガイドでは、ディクティックアトミック性に依存しないようアドバイスしています。詳細については、 Is Python variable assignment atomic?

組み込み型の原子性に依存しないでください。

辞書などのPythonの組み込みデータ型にはアトミック操作があるように見えますが、それらがアトミックでない場合があります(たとえば、__hash__または__eq__がPythonとして実装されている場合メソッド)とその原子性に依存しないでください。また、アトミック変数の割り当てに依存する必要もありません(これは辞書に依存するためです)。

スレッド間でデータを通信するための推奨される方法として、QueueモジュールのQueueデータ型を使用します。それ以外の場合は、スレッドモジュールとそのロックプリミティブを使用します。下位レベルのロックを使用する代わりにthreading.Conditionを使用できるように、条件変数の適切な使用について学習します。

そして、私はこれに同意します:CPythonにはすでにGILがあります。したがって、ロックを使用することによるパフォーマンスへの影響は無視できます。これらのCPython実装の詳細が1日変更されると、複雑なコードベースでバグを探すのに費やされる時間がはるかに高くなります。