全局变量如何在 Python 并行编程中工作?
Posted
技术标签:
【中文标题】全局变量如何在 Python 并行编程中工作?【英文标题】:How global variable works in parallel programming with Python? 【发布时间】:2021-12-16 15:24:00 【问题描述】:我有这个代码。在顺序方法中打印消息“no ok”,而在并行方法中,打印消息 ["ok", "ok", "ok"] 而不是 ["not ok", "not ok", "不好”] 我所期望的。
如何更改变量 globVar 而不将其作为“测试”函数中的参数?
import multiprocessing
global globVar
globVar = 'ok'
def test(arg1):
print(arg1)
return globVar
if __name__ == "__main__" :
globVar = 'not ok'
#Sequential
print(test(0))
#Parallel
pool = multiprocessing.Pool()
argList = [0,1,2]
result = pool.map(test,argList)
pool.close()
【问题讨论】:
子进程将脚本作为外部模块加载,因此它们会忽略if __name__ == '__main__'
位中的任何内容。所以他们看到globVar
,因为它是在它之外定义的,如'ok'
@AJ Biffl 谢谢你的回答。所以如果我把它作为参数,我只能修改变量 globVar 的值?
【参考方案1】:
TL;DR.您可以跳到最后一段以获得解决方案或阅读所有内容以了解实际情况。
您没有使用您的平台(例如windows
或linux
)标记您的问题,作为发布带有multiprocessing
标记的问题的指南要求您这样做;全局变量的行为(盎格鲁语的“行为”)很大程度上取决于平台。
在使用spawn
方法创建新进程的平台(例如 Windows)上,在使用 pool = multiprocessing.Pool()
语句创建的池中创建和初始化每个进程时,会创建一个新的空地址空间并创建一个新的启动 Python 解释器,重新读取并重新执行源程序,以便在最终调用工作函数 test
之前初始化地址空间。这意味着全局范围内的每个语句,即导入语句、变量声明、函数声明等,都是为此目的而执行的。但是,在新的子流程变量中,__name__
将 not 为“__main__”,因此不会执行 if __name__ == "__main__" :
块中的任何语句。这就是为什么对于 Windows 平台,您必须将创建新进程的代码放在这样的块中。如果不这样做,将导致无限递归的进程创建循环,否则未被检测到。
因此,如果您在 Windows 下运行,您的主进程在创建池之前已将 globVar
设置为“不正常”。但是,当进程在调用test
之前被初始化时,您的源代码会被重新执行,并且每个进程(在其自己的地址空间中运行,因此拥有自己的globVar
副本)将该变量重新初始化回'ok'。 那 是test
将看到的值,前面的语句暗示修改globVar
的本地副本不会反映回主进程。
现在在使用fork
创建新进程的平台上,例如Linux
,情况有些不同。创建子进程时,每个子进程都以只读方式继承父进程的地址空间,并且只有在尝试修改内存时才会获得副本(“写入时复制”)。这显然是一种更有效的流程创建机制。所以在这种情况下,test
将看到globVar
的值为“not ok”,因为这是创建子流程时的值。但是如果test
更新globVar
,“写入时复制”机制将确保它正在更新存在于本地地址空间中的globVar
。所以再次主进程不会看到更新的值。
因此,让工作函数返回值作为test
函数正在执行的操作是反映主进程结果的标准方式。 您的问题是 您没有以您期望的 globVar
值开始。这可以通过使用正确的 globVar
值初始化池的进程来解决initializer 和 initargs 参数到Pool
构造函数(参见documentation):
import multiprocessing
global globVar
globVar = 'ok'
def init_processes(gVar):
global globVar
globVar = gVar
def test(arg1):
print(arg1)
return globVar
if __name__ == "__main__" :
globVar = 'not ok'
#Sequential
print(test(0))
#Parallel
pool = multiprocessing.Pool(initializer=init_processes, initargs=(globVar,))
argList = [0,1,2]
result = pool.map(test,argList)
pool.close()
print(result)
打印:
0
not ok
0
1
2
['not ok', 'not ok', 'not ok']
【讨论】:
感谢您的回答!它有效,您帮助我了解了问题所在。以上是关于全局变量如何在 Python 并行编程中工作?的主要内容,如果未能解决你的问题,请参考以下文章