multiprocessing.Manager()を使うには?
質問
私は、以下の点について懸念しています。
multiprocessing.Manager()
について懸念があります。以下はその例です。
import multiprocessing
def f(ns):
ns.x *=10
ns.y *= 10
if __name__ == '__main__':
manager = multiprocessing.Manager()
ns = manager.Namespace()
ns.x = 1
ns.y = 2
print 'before', ns
p = multiprocessing.Process(target=f, args=(ns,))
p.start()
p.join()
print 'after', ns
と出力されます。
before Namespace(x=1, y=2)
after Namespace(x=10, y=20)
今までは、思ったとおりに動いていたのですが、このようにコードを修正しました。
import multiprocessing
def f(ns):
ns.x.append(10)
ns.y.append(10)
if __name__ == '__main__':
manager = multiprocessing.Manager()
ns = manager.Namespace()
ns.x = []
ns.y = []
print 'before', ns
p = multiprocessing.Process(target=f, args=(ns,))
p.start()
p.join()
print 'after', ns
これで出力は
before Namespace(x=[], y=[])
after Namespace(x=[], y=[])
なぜ私が期待したようにリストが変更されなかったのか、困惑しています。何が起こったのかを理解するために、どなたか助けていただけませんか?
どのように解決するのですか?
マネージャプロキシオブジェクトは、コンテナ内の(管理されていない)Mutableオブジェクトに加えられた変更を伝搬することができません。ですから、言い換えれば、もしあなたが
manager.list()
オブジェクトがある場合、管理されたリスト自身への変更は他の全てのプロセスに伝搬されます。しかし、もし普通の Python のリスト
の内部
がある場合、内側のリストへのどんな変更も伝搬されません。なぜなら、マネージャは変更を検出する方法がないからです。
変更を反映させるためには、リスト内で
manager.list()
オブジェクトを使う必要があります (要
Python 3.6 またはそれ以降
が必要です)、あるいは
manager.list()
オブジェクトを直接修正する必要があります(メモを参照
にある
manager.list
Python 3.5 またはそれ以前のバージョンでは
).
例えば、以下のコードとその出力について考えてみましょう。
import multiprocessing
import time
def f(ns, ls, di):
ns.x += 1
ns.y[0] += 1
ns_z = ns.z
ns_z[0] += 1
ns.z = ns_z
ls[0] += 1
ls[1][0] += 1 # unmanaged, not assigned back
ls_2 = ls[2] # unmanaged...
ls_2[0] += 1
ls[2] = ls_2 # ... but assigned back
ls[3][0] += 1 # managed, direct manipulation
di[0] += 1
di[1][0] += 1 # unmanaged, not assigned back
di_2 = di[2] # unmanaged...
di_2[0] += 1
di[2] = di_2 # ... but assigned back
di[3][0] += 1 # managed, direct manipulation
if __name__ == '__main__':
manager = multiprocessing.Manager()
ns = manager.Namespace()
ns.x = 1
ns.y = [1]
ns.z = [1]
ls = manager.list([1, [1], [1], manager.list([1])])
di = manager.dict({0: 1, 1: [1], 2: [1], 3: manager.list([1])})
print('before', ns, ls, ls[2], di, di[2], sep='\n')
p = multiprocessing.Process(target=f, args=(ns, ls, di))
p.start()
p.join()
print('after', ns, ls, ls[2], di, di[2], sep='\n')
出力します。
before
Namespace(x=1, y=[1], z=[1])
[1, [1], [1], <ListProxy object, typeid 'list' at 0x10b8c4630>]
[1]
{0: 1, 1: [1], 2: [1], 3: <ListProxy object, typeid 'list' at 0x10b8c4978>}
[1]
after
Namespace(x=2, y=[1], z=[2])
[2, [1], [2], <ListProxy object, typeid 'list' at 0x10b8c4630>]
[2]
{0: 2, 1: [1], 2: [2], 3: <ListProxy object, typeid 'list' at 0x10b8c4978>}
[2]
ご覧の通り、新しい値が管理対象コンテナに直接割り当てられると変化し、管理対象コンテナ内のミュータブルコンテナに割り当てられると変化しません。しかし、ミュータブルコンテナが次に 再割り当て が管理対象コンテナに再割り当てされると、再び変更されます。ネストされた管理対象コンテナを使用することも有効で、親コンテナに割り当て直すことなく直接変更を検出します。
関連
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] 辞書を値で並べ替えるにはどうしたらいいですか?
-
[解決済み] リストが空かどうかを確認するにはどうすればよいですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] Pandasのデータフレーム内の文字列を'date'データ型に変換するにはどうしたらいいですか?
-
[解決済み] PySparkでデータフレームのカラムをString型からDouble型に変更する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] データフレームをソートした後にインデックスを更新する
-
[解決済み] DataFrameに日付間の日数カラムを追加する pandas
-
[解決済み] Django Rest Framework ファイルアップロード
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] オブジェクトのリストに特定の属性値を持つオブジェクトが含まれているかどうかをチェックする
-
[解決済み] Pythonでマルチプロセッシングキューを使うには?
-
[解決済み] Cythonのコードを含むPythonパッケージはどのように構成すればよいのでしょうか?
-
[解決済み] Celeryタスクのユニットテストはどのように行うのですか?
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複