Python多进程Pool中全局列表变量返回为空的问题
多进程中全局变量无法同步的问题
我声明了空列表bulb_data作为全局变量并完成赋值,但用multiprocessing.Pool做多进程处理时,子进程里这个全局变量是空列表,不是已经赋值的内容。另外我还需要在每个子进程里编辑这个字典列表,并同步更新全局变量。
代码示例
from multiprocessing import Process, Pool camera_data = [{"id": "1", "url": "cam-c.jpg", "area": "1"}, {"id": "2", "url": "cam-d.jpg", "area": "1"}, {"id": "3", "url": "cam-e.jpg", "area": "2"}, {"id": "4", "url": "cam-f.jpg", "area": "2"}] bulb_data = [] def framed_images(fake): print(bulb_data) if __name__ == '__main__': print("camera_data - ",camera_data) for data in camera_data: bulb_data.append({"url": data["url"], "bulb": False}) print("bulb_data - ",bulb_data) fake_Data = bulb_data with Pool(processes=4) as pool: pool.map(framed_images, fake_Data)
当前输出
camera_data - [{'id': '1', 'url': 'cam-c.jpg', 'area': '1'}, {'id': '2', 'url': 'cam-d.jpg', 'area': '1'}, {'id': '3', 'url': 'cam-e.jpg', 'area': '2'}, {'id': '4', 'url': 'cam-f.jpg', 'area': '2'}] bulb_data - [{'url': 'cam-c.jpg', 'bulb': False}, {'url': 'cam-d.jpg', 'bulb': False}, {'url': 'cam-e.jpg', 'bulb': False}, {'url': 'cam-f.jpg', 'bulb': False}] [] [] [] []
期望输出
[{'url': 'cam-c.jpg', 'bulb': False}, {'url': 'cam-d.jpg', 'bulb': False}, {'url': 'cam-e.jpg', 'bulb': False}, {'url': 'cam-f.jpg', 'bulb': False}] [{'url': 'cam-c.jpg', 'bulb': False}, {'url': 'cam-d.jpg', 'bulb': False}, {'url': 'cam-e.jpg', 'bulb': False}, {'url': 'cam-f.jpg', 'bulb': False}] [{'url': 'cam-c.jpg', 'bulb': False}, {'url': 'cam-d.jpg', 'bulb': False}, {'url': 'cam-e.jpg', 'bulb': False}, {'url': 'cam-f.jpg', 'bulb': False}] [{'url': 'cam-c.jpg', 'bulb': False}, {'url': 'cam-d.jpg', 'bulb': False}, {'url': 'cam-e.jpg', 'bulb': False}, {'url': 'cam-f.jpg', 'bulb': False}]
问题原因
多进程模式下,子进程会复制父进程的内存空间,但这个复制是初始化时的快照——你在if __name__ == '__main__'里给bulb_data赋值的操作,是在父进程启动后执行的,子进程启动时只会拿到全局变量初始的空列表,不会同步父进程后续的修改。另外,子进程对全局变量的修改也不会影响父进程或其他子进程,因为每个进程都有独立的内存空间。
解决方法
方法1:用initializer传递初始数据给子进程
如果只需要子进程拿到bulb_data的初始值,不需要同步修改结果,可以在创建Pool时指定初始化函数,把数据传递给每个子进程:
from multiprocessing import Pool camera_data = [{"id": "1", "url": "cam-c.jpg", "area": "1"}, {"id": "2", "url": "cam-d.jpg", "area": "1"}, {"id": "3", "url": "cam-e.jpg", "area": "2"}, {"id": "4", "url": "cam-f.jpg", "area": "2"}] bulb_data = [] def init_worker(data): global bulb_data bulb_data = data.copy() # 将父进程的数据复制到子进程的全局变量 def framed_images(fake): # 在这里编辑bulb_data,比如修改对应url的bulb状态 for item in bulb_data: if item["url"] == fake["url"]: item["bulb"] = True print(bulb_data) if __name__ == '__main__': print("camera_data - ",camera_data) for data in camera_data: bulb_data.append({"url": data["url"], "bulb": False}) print("bulb_data - ",bulb_data) fake_Data = bulb_data with Pool(processes=4, initializer=init_worker, initargs=(bulb_data,)) as pool: pool.map(framed_images, fake_Data)
方法2:用共享内存实现跨进程同步修改
如果需要子进程修改后的数据能同步回父进程或其他子进程,要使用multiprocessing.Manager提供的共享数据结构:
from multiprocessing import Pool, Manager camera_data = [{"id": "1", "url": "cam-c.jpg", "area": "1"}, {"id": "2", "url": "cam-d.jpg", "area": "1"}, {"id": "3", "url": "cam-e.jpg", "area": "2"}, {"id": "4", "url": "cam-f.jpg", "area": "2"}] def framed_images(args): fake, bulb_data = args # 修改共享列表中的元素,所有进程都会看到变化 for item in bulb_data: if item["url"] == fake["url"]: item["bulb"] = True print(bulb_data) if __name__ == '__main__': print("camera_data - ",camera_data) # 创建Manager管理的共享列表 manager = Manager() bulb_data = manager.list() for data in camera_data: bulb_data.append({"url": data["url"], "bulb": False}) print("bulb_data - ",bulb_data) fake_Data = bulb_data # 将共享列表和任务参数一起传递给子进程 with Pool(processes=4) as pool: pool.map(framed_images, [(item, bulb_data) for item in fake_Data]) # 父进程可以直接获取修改后的结果 print("Final bulb_data: ", bulb_data)
注意事项
- 普通全局变量在多进程中完全独立,子进程的修改不会影响其他进程。
initializer方式性能更高,适合只需要传递初始数据的场景;Manager共享结构有一定性能开销,适合需要跨进程同步数据的场景。- 共享列表中的字典是可变对象,修改内部属性会自动同步,但如果多个子进程同时修改同一个元素,需要加锁(
multiprocessing.Lock)避免并发冲突。
内容的提问来源于stack exchange,提问作者Model Trainer
相关产品推荐
相关产品推荐

