multiprocessing (Python)中的全局变量



我为我的常见问题做了一个简单的(Python)代码示例。对于多处理代码,我需要为每个处理器执行def内的def。如果只使用一个def (def) -结果是ok的(我可以全局计数变量,因为它使用管理器)。但如果使用两级def (def) - result失败。在def中的任何更改都不会在def中应用。

from multiprocessing import Process, Manager
import os
def ff(b):
b = b +1
print('def ff b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()
def f(a):
b = 0
ff(b)
a.value = a.value + b
print('def f a = ', a.value, ' b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()
if __name__ == '__main__':
#a = ()
manager = Manager()
a = manager.Value('i', 0)
p = Process(target=f, args=(a,))
p.start()
p.join()
print('Main, a = ', a.value)
print('parent process:', os.getppid())
print('process id:', os.getpid())

这是结果

def ff b =  1
parent process: 12312
process id: 2320
def f a =  0  b =  0
parent process: 12312
process id: 2320
Main, a =  0
parent process: 21296
process id: 12312

我的期望:

def f return b = 1 and a = 1
Main return a = 1

我做错了什么?如何使内部处理全局变量?

您期望bf中成为1,因此a在父级中成为1。你的问题与multiprocessing或全局变量无关,你只是误解了Python的参数传递约定。你遇到的问题是,你不能改变bf通过改变一个函数,ff,它被传递给;int是不可变的,并且您不能将对名称的引用传递给函数,这样调用者的名称可以被反弹。

修改你的代码是微不足道的;不要尝试使用c++风格的引用传递来实现对b的更改(Python不能这样做),您需要返回新值(对更改/添加的行进行注释):

def ff(b):
b = b +1
print('def ff b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()
return b   # Return new b
def f(a):
b = 0
b = ff(b)  # Assign returned value back to b
a.value = a.value + b
print('def f a = ', a.value, ' b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()

就是这样。你所做的一切都成功了。

我想我明白问题所在了。我错误地声明了全局变量。全局变量的名称不能与defarg相同。最后,我想有:启动3个异步进程(3个不同的CPU)来执行一个def (def)。这个def将重复2次new def (def)。然后我将得到所有这些过程的最终结果。

这是我最后的代码,看起来工作得很好:

import os
from multiprocessing import Manager, Pool
def ff(c):
global b
c = c + 1
b = c
print('def ff, p.id:', os.getpid(), ', b=', b ,',c=', c)
def f(a):
global b
b = 0
for i in range(2):
ff(b)
a.value = a.value + b
print('def f, p.id:', os.getpid(), ', a=', a.value, ',b=', b)
if __name__ == '__main__':
manager = Manager()
a = manager.Value('i', 0)
cpu = 3
with Pool(cpu) as pool:
tasks = []
for m in range(2):
task = pool.apply_async(f, args=(a,))
tasks.append(task)
for task in tasks:
task.get()
print('Main, p.id:', os.getpid(), ', a=', a.value)

输出:

def ff, p.id: 20352 , b= 1 ,c= 1
def ff, p.id: 20352 , b= 2 ,c= 2
def ff, p.id: 29484 , b= 1 ,c= 1
def ff, p.id: 29484 , b= 2 ,c= 2
def f, p.id: 20352 , a= 2 ,b= 2
def f, p.id: 29484 , a= 4 ,b= 2
Main, p.id: 27004 , a= 4

我的最小可复制示例

import os
def ff(b):
b = b +1
print('def ff b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()

def f(a):
b = 0
ff(b)
a.value = a.value + b
print('def f a = ', a.value, ' b = ', b)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print()

class A:
value: int = 0
f(A())

这个输出:

def ff b =  1
parent process: 25356
process id: 8336
def f a =  0  b =  0
parent process: 25356
process id: 8336

为什么?

因为int是通过copy而不是ref传递的。所以当调用f(A())时,class A的实例是通过ref传递的(因为用户定义类的实例是可变的),但是当调用ff(b)时,b是通过copy传递的,所以b = b+1只在函数范围内工作,而不是在函数范围外。

相关内容

  • 没有找到相关文章

最新更新