如何在Python multiprocessing.map()中使用Value方法?解决NameError报错
问题描述
我正在测试多进程相关代码以理解其用法,但无法让multiprocessing.Value正常工作。运行代码时提示变量p不存在,请问我哪里出错了?
我的代码
from multiprocessing import Pool, Value from ctypes import c_int if __name__ == "__main__": p=Value(c_int,1) def addone(a): print(a) with p.get_lock(): print(p.value) p.value += 1 if __name__ == "__main__": with Pool() as po: po.map(addone,range(19)) print(p.value)
报错信息
multiprocessing.pool.RemoteTraceback: """ Traceback (most recent call last): File "C:\Users\(I removed this)\AppData\Local\Programs\Python\Python39\lib\multiprocessing\pool.py", line 125, in worker result = (True, func(*args, **kwds)) File "C:\Users\(I removed this)\AppData\Local\Programs\Python\Python39\lib\multiprocessing\pool.py", line 48, in mapstar return list(map(*args)) File "C:\Users\(I removed this)\Desktop\Python\make\multiTest.py", line 10, in addone with p.get_lock(): NameError: name 'p' is not defined """ The above exception was the direct cause of the following exception: Traceback (most recent call last): File (I removed this), line 15, in <module> po.map(addone,range(19)) File "C:\Users\(I removed this)\AppData\Local\Programs\Python\Python39\lib\multiprocessing\pool.py", line 364, in map return self._map_async(func, iterable, mapstar, chunksize).get() File "C:\Users\(I removed this)\AppData\Local\Programs\Python\Python39\lib\multiprocessing\pool.py", line 771, in get raise self._value NameError: name 'p' is not defined
问题原因与解决方法
原因
你在if __name__ == "__main__":块内定义了p,而addone函数运行在子进程中时,子进程不会执行主模块的__main__代码块,因此子进程的内存空间里根本不存在p变量,触发NameError。另外Pool默认不会主动将主进程的全局变量传递给子进程,子进程拥有独立的内存空间,无法直接访问主进程创建的Value对象。
解决方法
方法1:通过initializer传递共享变量
利用Pool的初始化参数,将共享变量注入每个子进程的全局空间:
from multiprocessing import Pool, Value from ctypes import c_int def init_worker(shared_p): global p p = shared_p def addone(a): print(a) with p.get_lock(): print(p.value) p.value += 1 if __name__ == "__main__": p = Value(c_int, 1) with Pool(initializer=init_worker, initargs=(p,)) as po: po.map(addone, range(19)) print(p.value)
initializer指定子进程启动时执行的初始化函数,initargs是传递给该函数的参数。- 在初始化函数里把共享变量赋值给子进程的全局
p,让addone能正常访问。
方法2:使用Manager创建可传递的共享变量
Manager创建的共享对象可以直接作为参数传递给子进程函数,适配Pool的使用场景:
from multiprocessing import Pool, Manager from ctypes import c_int def addone(a, shared_p): print(a) with shared_p.get_lock(): print(shared_p.value) shared_p.value += 1 if __name__ == "__main__": with Manager() as manager: p = manager.Value(c_int, 1) with Pool() as po: # 用starmap传递多个参数 po.starmap(addone, [(num, p) for num in range(19)]) print(p.value)
Manager.Value创建的共享变量支持跨进程传递,可直接作为函数参数传入。- 因为
map只能传递单个参数,所以改用starmap来传递包含多个参数的元组列表。
关键注意点
- 操作共享变量时必须加锁(
get_lock()),防止多个进程同时修改引发数据竞争,导致结果异常。 - Windows系统下多进程采用
spawn启动方式,子进程会重新导入主模块,因此主逻辑必须放在if __name__ == "__main__":块内,这一点你已经处理正确。
内容的提问来源于stack exchange,提问作者ok yes
相关产品推荐
相关产品推荐

