Python多进程修改字典后主线程无法同步变更问题求助
子进程修改字典后主线程无法获取变更的问题分析
环境与需求
- Python版本:3.9(3.12版本下结果一致)
- 需求目标:让子进程修改字典后,主线程能获取到这些变更
问题代码
import multiprocessing as mp import sys def my_func(result: dict): print(f'variable address at worker: {hex(id(result))}', file=sys.stderr) result["test"] = "test" print(f'{result}', file=sys.stderr) result = {} print(f'variable address at main thread: {hex(id(result))}', file=sys.stderr) my_worker = lambda : my_func(result) # 子进程执行 p = mp.Process(target=my_worker) p.start() p.join() print(f'result at main thread after execution: {result}', file=sys.stderr) # 同一进程内手动执行 my_worker() print(f'result at main thread after manual execution: {result}', file=sys.stderr) print(sys.version)
执行输出
variable address at main thread: 0x6ffffff39580 variable address at worker: 0x6ffffff39580 {'test': 'test'} result at main thread after execution: {} variable address at worker: 0x6ffffff39580 {'test': 'test'} result at main thread after manual execution: {'test': 'test'} 3.9.16 (main, Mar 8 2023, 22:47:22) [GCC 11.3.0]
问题原因
多进程的核心特性是每个进程拥有独立的内存空间。虽然打印的内存地址看起来相同,但这只是进程自身虚拟地址空间内的标识,不同进程的虚拟地址对应不同的物理内存。
子进程启动时,会通过**写时复制(Copy-on-Write)**机制复制父进程的内存数据。当子进程修改字典时,会在自己的内存空间里创建该字典的副本,修改的只是这个副本,和主进程的字典完全是两个独立对象,所以主线程看不到任何变更。
而直接调用my_worker()属于同一进程内的函数调用,修改的是同一个字典对象,所以主线程能看到结果。
解决方案
要实现跨进程的数据共享,需要使用multiprocessing模块提供的共享数据结构或进程间通信(IPC)机制,比如Manager().dict()、Queue或Pipe。这里以Manager为例:
修改后的代码
import multiprocessing as mp import sys def my_func(result): print(f'variable address at worker: {hex(id(result))}', file=sys.stderr) result["test"] = "test" print(f'{result}', file=sys.stderr) if __name__ == "__main__": # 使用Manager创建可跨进程共享的字典 with mp.Manager() as manager: result = manager.dict() print(f'variable address at main thread: {hex(id(result))}', file=sys.stderr) # 启动子进程执行 p = mp.Process(target=my_func, args=(result,)) p.start() p.join() print(f'result at main thread after execution: {result}', file=sys.stderr) # 同一进程内手动执行 my_func(result) print(f'result at main thread after manual execution: {result}', file=sys.stderr) print(sys.version)
方案说明
mp.Manager()会创建一个独立的服务进程,所有对manager.dict()的操作都会通过IPC转发到这个服务进程处理。这样,子进程和主进程操作的是同一个由服务进程维护的共享字典,修改会实时同步,主线程就能获取到子进程的变更。
内容的提问来源于stack exchange,提问作者Francisco Javier Rojas
相关产品推荐
相关产品推荐

