我为我的常见问题做了一个简单的(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
我做错了什么?如何使内部处理全局变量?
您期望b
在f
中成为1
,因此a
在父级中成为1
。你的问题与multiprocessing
或全局变量无关,你只是误解了Python的参数传递约定。你遇到的问题是,你不能改变b
在f
通过改变一个函数,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
只在函数范围内工作,而不是在函数范围外。