python多进程更新字典同步

use*_*325 4 python parallel-processing dictionary multiprocessing

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

inside function
{1: 1, 2: -1}
comes here
inside function
{1: 0, 2: 2}
comes here
{1: 0, 2: -1}
Run Code Online (Sandbox Code Playgroud)

谢谢.

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
Run Code Online (Sandbox Code Playgroud)

dna*_*naq 8

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

如果每个从属进程可以生成多个输出值,则可以谨慎地让每个从属进程向队列写入一个标记值,以向主节点发信号通知它已完成.那么代码可能看起来像:

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()
Run Code Online (Sandbox Code Playgroud)

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


sen*_*rle 5

你 import Manager,但你没有对它做任何事情。作为第一种方法,请执行以下操作:

a = Manager().dict({1: 0, 2: -1})
Run Code Online (Sandbox Code Playgroud)

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

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

manager = Manager()
a = manager.dict({1: 0, 2: -1})
b = manager.list((1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

请参阅Manager文档了解更多信息。

此外,您使用的锁是不必要的。TheManager会为您处理这些。正如文档所说,

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


Bos*_*ohn 0

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