2016-09-14 5 views
0

辞書が反復中にiteritems()を使用してサイズを変更した場合、Pythonは例外を発生させます。はpython dict.items()threadsafeですか?

私のプログラムはマルチスレッドで、別のスレッドがdictにキーを追加している間、私はdictを反復処理する必要がある場合があるので、私はこの問題に見舞われています。

幸いにも、dictのすべての要素に対して非常に正確な反復処理は必要ありません。したがって、私は反復を行うためにiteritems()の代わりにitems()を使用することを考えています。私はitems()は、dictの静的スナップショットを作成すると私は問題を回避すると思います。

私の質問はitems()実行時にdictのサイズが同時に変更されている場合は例外が発生しますか?

おかげ

優れたコメントとして
+1

私のアドバイス:疑問があるときは、ロックを使用してください: – mgilson

+0

おそらくitems()はそのスナップショットの構築の一部として辞書を繰り返し処理する必要があります。 item()を呼び出すと問題は解決しません。問題をコードからitems()メソッドの実装に移すだけです。より良い解決策は、ミューテックスを使用して辞書へのアクセスをシリアライズすることです。 –

+0

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htmはdict.keys()がアトミックであると言っていますが、items()はない。同じ記事では、「L1 [i:j] = L2」は原子であるが、「L [i] = L [j]」ではないということは奇妙なことである。その記事を信頼できますか? – abemaw

答えて

0

は注意:

  1. これは、スレッドセーフではありません。

  2. このような場合は、実際にロックを使用する必要があります。

the CPython source code, dictobject.cでこれを見ることが可能である:

あなたが機能itemsのために使用されている

static PyObject * 
dict_items(register PyDictObject *mp) 

を見れば、あなたはそれを見ることができます(いくつかの巧妙な事前割り当てた後、結果として)、基本的に配列mp->ma_tableを反復します(マスクを使用してエントリがある場所を確認します)。今、あなたは、テーブルのサイズを変更する必要がある場合に使用されている機能

static int 
dictresize(PyDictObject *mp, Py_ssize_t minused) 

を見れば

、あなたはma_tableの要素は完全に別のバッファに移動することができることを確認し、それをすることができますPYMem_Freeを使用して解放できます。

これは、物事が同期せずに並行して実行される場合、ガーベージメモリにアクセスする危険性が非常に高いためです。

関連する問題