4

我正在尝试通过多个进程更新一本通用词典。你能帮我找出这段代码有什么问题吗?我得到以下输出:

inside function
{1: 1, 2: -1}
comes here
inside function
{1: 0, 2: 2}
comes here
{1: 0, 2: -1}

谢谢。

from multiprocessing import Lock, Process, Manager

l= Lock()


def computeCopyNum(test,val):
    l.acquire()
    test[val]=val
    print "inside function"
    print test
    l.release()
    return

a=dict({1: 0, 2: -1})

procs=list()

for i in range(1,3):
    p = Process(target=computeCopyNum, args=(a,i))
    procs.append(p)
    p.start()

for p in procs:
p.join()
    print "comes here"

print a
4

3 回答 3

9

答案其实很简单。您正在使用 multiprocessing 模块,您可以使用它启动几个不同的 python 进程。不同的进程有不同的地址空间并且它们不共享内存,所以你的所有进程都会写入它们自己的本地字典副本。

使用多处理模块时进行进程间通信的最简单方法是使用队列在从属进程和主进程之间进行通信。

from multiprocessing import Process, Queue

def computeCopyNum(queue, val):
    queue.put(val) # can also put a tuple of thread-id and value if we would like to

procs=list()

queue = Queue()
for i in range(1,3):
    p = Process(target=computeCopyNum, args=(queue, i))
    procs.append(p)
    p.start()

for _ in procs:
    val = queue.get()
    # do whatever with val

for p in procs:
    p.join()

如果每个从属进程都可以生成多个输出值,那么让每个从属进程将一个哨兵值写入队列以向主进程发出信号表明它已经完成可能是谨慎的。然后代码可能看起来像:

def slave(queue):
    for i in range(128): # just for example
        val = #some calculated result
        queue.put(val)

    queue.put(None) # add a sentinel value to tell the master we're done

queue = Queue()

# spawn 32 slave processes
num_procs = 32
procs = [Process(target=slave, args=(queue, )) for _ in range(num_procs)]
for proc in procs: 
    proc.start()

finished = 0
while finished < num_procs:
    item = queue.get()
    if item is None: 
        finished += 1
    else: 
        # do something with item

for proc in procs: 
    proc.join()

您也可以使用管理器,如另一个答案所示。这种方法的问题是可能会在进程地址空间之间发生大量隐式内存复制,这很难推理。我总是更喜欢使用显式队列。

于 2012-09-21T21:56:29.217 回答
5

你 import Manager,但你不做任何事情。作为第一种方法,请改为:

a = Manager().dict({1: 0, 2: -1})

全局变量在使用multiprocessing. 子进程只能访问副本,并且它们所做的更改在退出时会被遗忘,除非您使用的是专门设计的能够在进程之间传播信息的对象。

在进程之间传递数据有许多不同的选择,但使用上述Manager对象通常是最简单的。您还可以使用该Manager对象创建多个共享对象:

manager = Manager()
a = manager.dict({1: 0, 2: -1})
b = manager.list((1, 2, 3))

有关更多信息,请参阅Manager文档。

此外,您使用的锁是不必要的。Manager会为您解决这个问题。正如文档所说,

通常同步原语在多进程程序中不像在多线程程序中那样需要。

于 2012-09-21T21:40:05.050 回答
0

进程不像线程那样共享内存。每个进程都以它自己的独立副本结束。如果您想在不同的线程中工作,则需要使用管道或其他一些进程间通信将数据返回到中央进程。

于 2012-09-21T21:39:53.687 回答