Python の multiprocessing.Manager は、プロセス間で共有できるオブジェクトを提供するクラスです。Value や Array と違い、リストや辞書などの複雑なデータ構造も共有できます。
Manager の基本
Manager() は共有オブジェクトを管理するサーバープロセスを起動します。
from multiprocessing import Process, Manager def worker(shared_list): shared_list.append("Hello from child") if __name__ == "__main__": with Manager() as manager: shared_list = manager.list() p = Process(target=worker, args=(shared_list,)) p.start() p.join() print(shared_list) # ['Hello from child']
manager.list() で共有リストを作成し、子プロセスから変更を加えられます。
Manager が提供する共有オブジェクト
Manager は様々な共有データ構造を提供します。
| list() | 共有リスト |
| dict() | 共有辞書 |
| Value(typecode, value) | 共有値 |
| Array(typecode, sequence) | 共有配列 |
| Namespace() | 属性を持つオブジェクト |
| Queue() | 共有キュー |
| Lock() | 共有ロック |
| Event() | 共有イベント |
共有辞書を使う
manager.dict() で共有辞書を作成できます。
from multiprocessing import Process, Manager def update_dict(d, key, value): d[key] = value if __name__ == "__main__": with Manager() as manager: shared_dict = manager.dict() processes = [] for i in range(3): p = Process(target=update_dict, args=(shared_dict, f"key{i}", i)) processes.append(p) p.start() for p in processes: p.join() print(dict(shared_dict)) # {'key0': 0, 'key1': 1, 'key2': 2}
複数のプロセスから同時に辞書を更新できます。
Namespace を使う
Namespace は属性を持つシンプルなオブジェクトです。
from multiprocessing import Process, Manager def update_namespace(ns): ns.count += 1 ns.name = "Updated" if __name__ == "__main__": with Manager() as manager: ns = manager.Namespace() ns.count = 0 ns.name = "Initial" p = Process(target=update_namespace, args=(ns,)) p.start() p.join() print(ns.count) # 1 print(ns.name) # Updated
設定値の共有などに便利です。
Manager と Value/Array の違い
Value/Array
共有メモリを直接使う。高速だが、ctypes の型に限定される。
Manager
サーバープロセス経由でアクセス。柔軟だが、オーバーヘッドが大きい。
パフォーマンスが重要な場合は Value や Array を、柔軟性が必要な場合は Manager を使います。
ネストしたオブジェクトの注意点
Manager のリストや辞書で、ネストしたオブジェクトを変更する場合は注意が必要です。
from multiprocessing import Manager with Manager() as manager: shared_list = manager.list([[1, 2], [3, 4]]) # これは反映されない shared_list[0].append(5) print(shared_list[0]) # [1, 2] のまま # 正しい方法 temp = shared_list[0] temp.append(5) shared_list[0] = temp print(shared_list[0]) # [1, 2, 5]
ネストしたオブジェクトへの変更は、明示的に再代入しないと反映されません。
SyncManager のカスタマイズ
Manager を継承して、カスタムの共有オブジェクトを作ることもできます。
from multiprocessing.managers import BaseManager class Counter: def __init__(self): self._value = 0 def increment(self): self._value += 1 return self._value def value(self): return self._value class MyManager(BaseManager): pass MyManager.register('Counter', Counter) if __name__ == "__main__": with MyManager() as manager: counter = manager.Counter() print(counter.increment()) # 1 print(counter.increment()) # 2
独自のクラスを register() で登録して、プロセス間で共有できます。