问题在于每个进程都在自己的地址空间中运行,因此拥有自己正在更新的全局变量副本。实际上,如果您在使用 fork 来创建新进程的平台上运行(顺便说一下,您应该使用您运行的平台标记您的问题 - - 这很重要),每个新创建的进程都从创建新进程时主进程拥有的地址空间的副本开始,但是当它修改该地址空间中的任何内容时,就会制作一个新副本(复制-写语义)。因此,新创建的进程对全局变量所做的任何更改都不会反映回主进程。然而:
如果您使用multiprocessing.Value 在共享内存中创建变量,例如a = multiprocessing.Value('i', 0, lock=False),则a 是对指向某个位置的值的引用,该位置是共享内存,任何地址中的任何进程都可以访问空间,即使此引用被复制,它仍然有效:
import multiprocessing
a = multiprocessing.Value('i', 0, lock=False)
maxA = multiprocessing.Value('i', 0, lock=False)
s1 = """
global a
a.value = 1"""
s2 = """
global a
a.value = 2"""
inputs = [s1, s2]
maxA.value = 0
a.value = 0
def Execute_For_Multiprocessing(s):
exec(s)
global maxA
maxA.value = max(maxA.value, a.value)
print(maxA.value)
return
for s in inputs:
p = multiprocessing.Process(target=Execute_For_Multiprocessing, args = [s])
p.start()
p.join()
print(maxA.value)
打印:
1
2
2
为 Windows 修改的相同程序:
import multiprocessing
a = multiprocessing.Value('i', 0, lock=False)
maxA = multiprocessing.Value('i', 0, lock=False)
def Execute_For_Multiprocessing(s):
exec(s)
global maxA
maxA.value = max(maxA.value, a.value)
print(maxA.value)
return
# required for Windows:
if __name__ == '__main__':
s1 = """
global a
a.value = 1"""
s2 = """
global a
a.value = 2"""
inputs = [s1, s2]
maxA.value = 0
a.value = 0
for s in inputs:
p = multiprocessing.Process(target=Execute_For_Multiprocessing, args = [s])
p.start()
p.join()
print(maxA.value)
打印:
1
2
0
这对 Windows 不起作用的原因是 Windows 使用 spawn 方法启动新进程。这意味着新进程的初始化相当于创建一个新的空地址空间,然后启动一个新的 Python 解释器,该解释器通过重新读取源程序并在全局范围内执行所有语句来初始化该地址,然后才这样做调用您指定的目标函数。但这样做时,每个新创建的进程都在重新执行创建 multiprocessing.Value 实例的语句,因此将不再引用主进程创建的相同实例。
解决方案是将主进程创建的共享内存值传递给子进程,并让子进程使用这些值初始化全局内存:
import multiprocessing
def Execute_For_Multiprocessing(s, v1, v2):
global maxA, a
maxA = v1
a = v2
exec(s)
maxA.value = max(maxA.value, a.value)
print(maxA.value)
return
# required for Windows:
if __name__ == '__main__':
s1 = """
global a
a.value = 1"""
s2 = """
global a
a.value = 2"""
inputs = [s1, s2]
a = multiprocessing.Value('i', 0, lock=False)
maxA = multiprocessing.Value('i', 0, lock=False)
# These statements are actually unnecessary:
#maxA.value = 0
#a.value = 0
for s in inputs:
p = multiprocessing.Process(target=Execute_For_Multiprocessing, args = [s, maxA, a])
p.start()
p.join()
print(maxA.value)
打印:
1
2
2
当然,此代码也适用于使用 fork 的平台,例如 Linux。