python多进程更新字典同步

时间:2012-09-21 21:35:38

标签: python dictionary parallel-processing multiprocessing

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

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

3 个答案:

答案 0 :(得分:7)

答案其实很简单。您正在使用多处理模块,您可以使用该模块启动多个不同的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()

如果每个从属进程都可以生成多个输出值,那么让每个从属进程向队列写一个sentinel-value以向主站发信号通知它已经完成是明智的。然后代码可能看起来像:

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()

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

答案 1 :(得分:4)

您导入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会为您处理。正如docs所说,

  

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

答案 2 :(得分:0)

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