Python3多处理共享对象

2024-05-13 09:25:53 发布

您现在位置:Python中文网/ 问答频道 /正文

在使用python3.2.3(debian7.5)中的multiprocessing模块时,我偶然发现了一个共享对象的同步问题。我用这个简单的例子来说明这个问题,它的功能类似于multiprocessing.Pool.map(我能想到的最简单的)。我使用multiprocessing.Manager,因为我的原始代码使用它(通过网络同步)。但是如果我使用一个简单的multiprocessing.Value作为计数器变量,则其行为是相同的。在

import os as os
import sys as sys
import multiprocessing as mp

def mp_map(function, obj_list, num_workers):
    """ 
    """
    mang = mp.Manager()
    jobq = mang.Queue()
    resq = mang.Queue()
    counter = mp.Value('i', num_workers, lock=True)
    finished = mang.Event()
    processes = []
    try:
        for i in range(num_workers):
            p = mp.Process(target=_parallel_execute, kwargs={'execfun':function, 'jobq':jobq, 'resq':resq, 'counter':counter, 'finished':finished})
            p.start()
            p.join(0)
            processes.append(p)
        for item in obj_list:
            jobq.put(item)
        for i in range(len(processes)):
            jobq.put('SENTINEL')
        finished.wait()
        for p in processes:
            if p.is_alive():
                p.join(1)
                p.terminate()
    except Exception as e:
        for p in processes:
            p.terminate()
        raise e
    results = []
    for item in iter(resq.get, 'DONE'):
        results.append(item)
    return results

def _parallel_execute(execfun, jobq, resq, counter, finished):
    """
    """
    for item in iter(jobq.get, 'SENTINEL'):
        item = execfun(item)
        resq.put(item)
    counter.value -= 1
    print('C: {}'.format(counter.value))
    if counter.value <= 0:
        resq.put('DONE')
        finished.set()
    return


if __name__ == '__main__':
    l = list(range(50))
    l = mp_map(id, l, 2)
    print('done')
    sys.exit(0)

运行上述代码几次会导致以下结果:

^{pr2}$

根据multiprocessing模块的文档,我不明白为什么counter不是进程安全的,因为对它的访问是通过Manager管理的,而且它显然是用lock=True初始化的。由于死锁只是偶尔发生,所以我不太确定如何解释这种行为。任何有帮助的见解都非常感谢,谢谢。在

编辑: 碰巧我在google上搜索了一点之后发现了一个解释;如果其他人感兴趣,我将在这里分享:基于下面链接的博客条目1,Python中完成的锁定(即在multiprocessing.[Manager].Value中使用lock=True)不会导致对共享值的原子操作,如示例所示。解决方案是使用进程之间共享的另一个锁,用于控制对共享对象的访问。在

[http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing/]


Tags: inmapforputascountermanagermp
1条回答
网友
1楼 · 发布于 2024-05-13 09:25:53

按照罗斯的建议,我在这里重复答案: 简而言之,lock=Truefor multiprocessing.Valuemultiprocessing.Manager.Value不会使值的增量(减量)成为原子操作-需要单独的锁来封装整个操作;有关代码示例,请参阅此答案https://stackoverflow.com/a/1233363/3826372或上述博客条目http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing

相关问题 更多 >