python中的列表和多处理

python中的列表和多处理,python,Python,我在多处理过程中遇到了一些奇怪的python问题。下面是一个简化的python程序,说明了该问题: from multiprocessing import Process import time varcol = {"list": []} def addelement(varcol): varcol["list"].append(1) addelement(varcol) print(len(varcol["list"])) def addelement_mp(varco

我在多处理过程中遇到了一些奇怪的python问题。下面是一个简化的python程序,说明了该问题:

from multiprocessing import Process
import time


varcol = {"list": []}


def addelement(varcol):
    varcol["list"].append(1)


addelement(varcol)
print(len(varcol["list"]))


def addelement_mp(varcol):
    varcol["list"].append(2)
    print(len(varcol["list"]))


p = Process(target=addelement_mp, args=(varcol,))
p.start()

time.sleep(5)
print(len(varcol["list"]))
我想知道为什么上述python程序的输出是:

1
2
1
而不是:

1
2
2

当您使用多进程打开第二个进程时,将创建一个全新的Python实例,该实例具有自己的全局状态。该全局状态不共享,因此子进程对全局变量所做的更改对父进程不可见

如果希望在不同进程之间共享变量,请使用多线程而不是多处理

from threading import Thread
import time

varcol = {"list": []}


def addelement(varcol):
    varcol["list"].append(1)


addelement(varcol)
print(len(varcol["list"]))


def addelement_mp(varcol):
    varcol["list"].append(2)
    print(len(varcol["list"]))


p = Thread(target=addelement_mp, args=(varcol,))
p.start()

time.sleep(1)
print(len(varcol["list"]))
或者您可以尝试使用回调函数

from multiprocessing import Pool

varcol = {"list": []}


def addelement(varcol):
    varcol["list"].append(1)


addelement(varcol)
print(len(varcol["list"]))   # Always print 1


def addelement_mp(varcol):
    varcol["list"].append(2)
    print(len(varcol["list"]))
    return varcol


def confirm_len(varcol):
    print(len(varcol[0]["list"]))


pool=Pool()
# Will First Call addelement_mp and then call confirm_len with addelement_mp return value as its argv.
r = pool.map_async(addelement_mp, (varcol,), callback=confirm_len)
r.wait()
如果不想创建新的回调函数,则可以使用multiprocessing.Pool.map执行多处理

print len(pool.map(addelement_mp, [varcol])[0]["list"])

当您启动一个新进程时,python使用
fork()
,这将创建一个具有与父进程完全相同的数据的子进程,但这些数据位于不同的地址。考虑此代码,可以看到在变量地址(在Windows 10、Python 3.6上测试):<>代码> For()/Cuff>:

示例输出:

0x18d0aa39af8
multiprocess address: -----
0x10f074f2a20
multiprocess address ended -----
0x18d0aa39af8

因此,正如您所看到的,子进程正在修改的对象与主进程的对象不同。

您确定要将1,2,1作为输出吗?您使用的是什么操作系统?Windows平台和非Windows平台之间开箱即用的多处理行为存在一些显著差异。@VanPeer是的,当然。。。我刚才试过了。这很奇怪。这就好像列表只是被复制并通过值而不是引用传递给子进程。@MarkDickinson我在linux Mint上。。。最新版本。从那以后,我做了一些变通来完成我正在做的事情。但是我确实浪费了很多时间试图弄清楚Python为什么会有这种意想不到的行为。无论如何,我认为正确的python方法是使用manager.list.OP,它询问的是代码为何以这种方式运行,而不是出于任何目的修改代码。P/S投了反对票的不是我。仅供参考。@van peer是,因为子进程对全局变量所做的更改将不可见这是不正确的。Python在Windows上不使用fork,因为Windows不提供fork操作。有关更多信息,请参阅多处理文档。啊,是的。我没有研究Python如何在Windows中实现它,我只是在我的Windows机器上简单地修改了代码。但是,不管实现细节如何,都适用相同的概念:子进程有自己的内存空间,这解释了不同的地址。谢谢@TuanDT,你可能是对的。。。事实上,在随后的阅读中,我发现有一个manager.list用于类似的事情。
0x18d0aa39af8
multiprocess address: -----
0x10f074f2a20
multiprocess address ended -----
0x18d0aa39af8