Python多处理和管理器

space_voyager

我正在使用Pythonmultiprocessing创建一个并行应用程序。流程需要共享一些数据,对此我使用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)好吗?

达克诺

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


对于您最初关于“良好形式”的问题。

IMO将子进程的main函数显式foo_parallel传递global_dict给泛型函数会更干净add(var)那将是依赖注入的一种形式,并具有一些优点。在您的示例中,并非十分详尽:

  • 允许隔离测试

  • 提高代码可重用性

  • 更容易的调试(检测被管理对象的不可访问性不应延迟,直到add被调用为止快速失败

  • 更少的样板代码(例如,需要多个功能的资源上的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)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章