具有面向对象python的进程之间的共享池映射

时间:2016-04-18 17:11:30

标签: python python-2.7 multiprocessing

(的 python2.7

我正在尝试做一种扫描程序,它必须遍历CFG节点,并在分支的不同进程中进行拆分以实现并行目的。

扫描仪由Scanner类的对象表示。这个类有一个方法遍历,它遍历所述图并在必要时拆分。

以下是它的外观:

class Scanner(object):
    def __init__(self, atrb1, ...):
       self.attribute1 = atrb1
       self.process_pool = Pool(processes=4)
    def traverse(self, ...):
        [...]
        if branch:
           self.process_pool.map(my_func, todo_list).

我的问题如下: 如何创建multiprocessing.Pool的实例,它在我的所有进程之间共享?我希望它被共享,因为由于路径可以再次拆分,我不想以一种叉炸弹结束,并且拥有相同的池将帮助我限制同时运行的进程数。 / p>

上述代码不起作用,因为Pool无法进行pickle。因此,我试过了:

class Scanner(object):
   def __getstate__(self):
      self_dict  = self.__dict__.copy()
      def self_dict['process_pool']
      return self_dict
    [...]

但显然,它导致在创建的进程中没有定义 self.process_pool

然后,我尝试创建一个Pool作为模块属性:

process_pool = Pool(processes=4)

def my_func(x):
    [...]

class Scanner(object):
    def __init__(self, atrb1, ...):
       self.attribute1 = atrb1
    def traverse(self, ...):
        [...]
        if branch:
           process_pool.map(my_func, todo_list)

它不起作用,这answer解释了原因。 但事情就是这样,无论我在哪里创建我的游泳池,都会遗漏一些东西。如果我在文件末尾创建了这个池,它就不会看到self.attribute1,就像它没有看到answer一样,并且因为AttributeError而失败。

我还没有尝试分享它,而且我已经陷入了多处理方式。

我不知道我是否一直没有正确思考整个事情,但我无法相信处理像“拥有工人池并给他们任务”这样简单的事情是如此复杂。

谢谢,

修改: 我解决了我的第一个问题(AttributeError),我的类有一个回调作为它的属性,并且这个回调是在主脚本文件中定义的,在导入扫描器模块之后...但并发和“不要炸弹”的东西仍然是一个问题。

1 个答案:

答案 0 :(得分:0)

您想要做的事情不能安全地完成。想想你是否以某种方式在父进程和工作进程之间共享一个共享Pool,例如,两个工作进程。父运行map,尝试执行两项任务,每项任务需要map两项任务。两个父调度任务分配给每个工作程序,父代阻塞。每个工作程序向共享池发送另外两个任务,并阻止它们完成。但是现在所有工人都被占领,等待工人自由;你已陷入僵局。

更安全的方法是让工作人员返回足够的信息以在父母中分派其他任务。然后你可以做类似的事情:

class MoreWork(object):
    def __init__(self, func, *args):
        self.func = func
        self.args = args

pool = multiprocessing.Pool()
try:
    base_task = somefunc, someargs
    outstanding = collections.deque([pool.apply_async(*base_task)])
    while outstanding:
        result = outstanding.popleft().get()
        if isinstance(result, MoreWork):
            outstanding.append(pool.apply_async(result.func, result.args))
        else:
            ... do something with a "final" result, maybe breaking the loop ...
finally:
     pool.terminate()

这些功能取决于您,当有更多事情要做时,他们只会在MoreWork中返回信息,而不是直接启动任务。关键在于确保通过让父母单独负责任务调度以及完全负责任务完成的工作人员,由于所有工作人员被阻塞等待队列中的任务而无法解决问题正在处理中。

这也完全没有优化;理想情况下,如果队列中的其他项目完成,您将不会阻止等待队列中的第一项;使用concurrent.futures模块,特别是使用concurrent.futures.wait等待来自任意数量的未完成任务的第一个可用结果,这样做更容易,但是您需要第三个派对PyPI包在Python 2.7上获得concurrent.futures