Pythonでは、スレッドを使用する際にオブジェクトはコピーなしでメモリ内のすべてのスレッドに即座にアクセス可能です。しかし、multiprocessingを使用してプロセス間で作業すると、標準のPythonオブジェクト(例えば、リスト、辞書)はシリアル化を介してプロセス間で渡され(通常はpickleを通じて)、各プロセスはオブジェクトのコピーを取得します。一つのプロセスでのオブジェクトの変更は、別のプロセスのコピーには反映されません。
multiprocessing.Manager().dict()のような特別な構造を使用する必要があります。# マルチプロセス from multiprocessing import Process, Manager def worker(d): d['a'] = 42 if __name__ == '__main__': # 通常のdictはプロセス間で動作しません managed_dict = Manager().dict() p = Process(target=worker, args=(managed_dict,)) p.start(); p.join() print(managed_dict['a']) # 42
どのような場合に、あるプロセスで通常のリスト(list)を編集すると別のプロセスに反映されますか?
マルチプロセスを使用している場合は決してありません。通常のPythonオブジェクトはプロセス間で共有されません。共有するには、状態をプロセス間で同期させる特別なプリミティブ—Managerオブジェクト(例えば、Manager().list()やManager().dict())を使用する必要があります。
逸話
ウェブクローラーの開発チームは、タスクキューをリストとして初期化し、マルチプロセスを介してそれをプロセス間で共有しました。タスクが「失われた」理由は、プロセスが互いの更新を見なかったからです。Manager().list()を使用するように修正しました。
逸話
分析サービスでは、ログをスレッド内のネストされたdictに収集しようとしました。高負荷のシナリオでは、これが競合状態を引き起こし、ロックがないためにデータが損傷しました。
逸話
ETLサービスでは、データ処理ステージ中に収集されたオブジェクトを複数のプロセスに収集しようとしたときに、データの重複/喪失が発生しました:プログラマーは各プロセスが共有の構造ではなく、自分のコピーで作業していることを考慮しませんでした。