辞書を保持するクラスがあります
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
を呼び出す前にロックを使用する必要がありますか?
Pythonの組み込み構造は、単一の操作に対してスレッドセーフですが、ステートメントが実際に複数の操作になる場所を確認するのが難しい場合があります。
コードは安全でなければなりません。留意してください:ここのロックはオーバーヘッドをほとんど追加しないので、安心できます。
http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm に詳細があります。
はい、組み込み型は本質的にスレッドセーフです: http://docs.python.org/glossary.html#term-global-interpreter-lock
これにより、同時アクセスに対して暗黙的に安全なオブジェクトモデル(dictなどの重要な組み込み型を含む)を作成することにより、CPythonの実装が簡素化されます。
Googleのスタイルガイドでは、ディクティックアトミック性に依存しないようアドバイスしています。詳細については、 Is Python variable assignment atomic?
組み込み型の原子性に依存しないでください。
辞書などのPythonの組み込みデータ型にはアトミック操作があるように見えますが、それらがアトミックでない場合があります(たとえば、
__hash__
または__eq__
がPythonとして実装されている場合メソッド)とその原子性に依存しないでください。また、アトミック変数の割り当てに依存する必要もありません(これは辞書に依存するためです)。スレッド間でデータを通信するための推奨される方法として、
Queue
モジュールのQueueデータ型を使用します。それ以外の場合は、スレッドモジュールとそのロックプリミティブを使用します。下位レベルのロックを使用する代わりにthreading.Condition
を使用できるように、条件変数の適切な使用について学習します。
そして、私はこれに同意します:CPythonにはすでにGILがあります。したがって、ロックを使用することによるパフォーマンスへの影響は無視できます。これらのCPython実装の詳細が1日変更されると、複雑なコードベースでバグを探すのに費やされる時間がはるかに高くなります。