【问题标题】:Python multiprocessing and ManagerPython 多处理和管理器
【发布时间】:2018-09-21 01:59:50
【问题描述】:

我正在使用 Python 的 multiprocessing 创建一个并行应用程序。进程需要共享一些数据,为此我使用Manager。但是,我有一些常用函数需要调用哪些进程,哪些需要访问Manager 对象存储的数据。我的问题是我是否可以避免需要将Manager 实例作为参数传递给这些常用函数,而不是像全局一样使用它。换句话说,考虑下面的代码:

import multiprocessing as mp

manager = mp.Manager()
global_dict = manager.dict(a=[0])

def add():
    global_dict['a'] += [global_dict['a'][-1]+1]

def foo_parallel(var):
    add()
    print var

num_processes = 5
p = []
for i in range(num_processes):
    p.append(mp.Process(target=foo_parallel,args=(global_dict,)))

[pi.start() for pi in p]
[pi.join() for pi in p]

这运行良好并在我的机器上返回p=[0,1,2,3,4,5]。然而,这是“好形式”吗?这是一个好方法吗,就像定义 add(var) 并改为调用 add(var) 一样好?

【问题讨论】:

    标签: python multithreading parallel-processing multiprocessing python-multiprocessing


    【解决方案1】:

    您的代码示例似乎比表单存在更大的问题。只有运气好才能获得所需的输出。重复执行会产生不同的结果。那是因为+= 不是原子操作。多个进程可以在其中任何一个更新它之前一个接一个地读取相同的旧值,并且它们将写回相同的值。为了防止这种行为,您必须另外使用Manager.Lock


    关于“良好形式”的原始问题。

    IMO 会更简洁,让子进程 foo_parallel 的主函数将 global_dict 显式传递给通用函数 add(var)。那将是dependency injection 的一种形式,并且具有一些优势。在您的示例中,并非详尽无遗:

    • 允许隔离测试

    • 提高代码可重用性

    • 更容易调试(检测托管对象的不可访问性不应延迟到调用add (fail fast) 后)

    • 更少的样板代码(例如,多个函数需要的资源上的 try-excepts 块)

    作为旁注。仅针对其副作用使用列表推导被认为是“代码气味”。如果您不需要列表作为结果,只需使用 for 循环即可。

    代码:

    import os
    from multiprocessing import Process, Manager
    
    
    def add(l):
        l += [l[-1] + 1]
        return l
    
    
    def foo_parallel(global_dict, lock):
        with lock:
            l = global_dict['a']
            global_dict['a'] = add(l)
            print(os.getpid(), global_dict)
    
    
    if __name__ == '__main__':
    
        N_WORKERS = 5
    
        with Manager() as manager:
    
            lock = manager.Lock()
            global_dict = manager.dict(a=[0])
    
            pool = [Process(target=foo_parallel, args=(global_dict, lock))
                    for _ in range(N_WORKERS)]
    
            for p in pool:
                p.start()
    
            for p in pool:
                p.join()
    
            print('result', global_dict)
    

    【讨论】:

      猜你喜欢
      • 2013-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-13
      • 2022-01-21
      • 2023-04-05
      • 1970-01-01
      相关资源
      最近更新 更多