Python如何在类中进行多处理?

时间:2015-03-12 12:27:35

标签: python multiprocessing

我的代码结构如下所示:

Class A:
  def __init__(self):
    processes = []
    for i in range(1000):
      p = Process(target=self.RunProcess, args=i)
      processes.append[p]

    # Start all processes
    [x.start() for x in processes]

  def RunProcess(self, i):
    do something with i...

主要剧本:

myA = A()

我似乎无法让它运行。我收到运行时错误“尝试在启动之前启动新进程         当前流程已完成其自举阶段。

如何让多个处理工作?如果我使用线程,它运行正常,但它和顺序一样慢...而且我也担心多次处理也会很慢,因为创建进程需要更长的时间?

有什么好的提示吗?非常感谢提前。

3 个答案:

答案 0 :(得分:6)

我可以在您的代码中看到一些语法问题:

  • args Process期待一个元组,你传递一个整数,请将第5行更改为:

    p = Process(target=self.RunProcess, args=(i,))

  • list.append是一种方法,传递给它的参数应该包含在()中,而不是[]中,请将第6行更改为:

    processes.append(p)

正如@qarma指出的那样,在类构造函数中启动进程并不是一个好习惯。我将按如下方式构造代码(调整您的示例):

import multiprocessing as mp
from time import sleep

class A(object):
    def __init__(self, *args, **kwargs):
        # do other stuff
        pass

    def do_something(self, i):
        sleep(0.2)
        print('%s * %s = %s' % (i, i, i*i))

    def run(self):
        processes = []

        for i in range(1000):
            p = mp.Process(target=self.do_something, args=(i,))
            processes.append(p)

        [x.start() for x in processes]


if __name__ == '__main__':
    a = A()
    a.run()

答案 1 :(得分:4)

它应该简化您使用Pool的内容。就速度而言,启动流程确实需要时间。但是,使用Pool而不是njobs运行Process应该与使用进程运行它一样快。 Pool的默认设置(如下所示)是使用可用的最大进程数(即您拥有的CPU数),并在作业完成后立即为工作人员提供新的工作。你不会得到njobs - 并行方式,但是你可以获得你的CPU可以处理的并行性,而无需超额订阅处理器。我正在使用pathos,其分叉为multiprocessing,因为它比标准multiprocessing更强大......而且,我也是作者。但你可以使用multiprocessing来实现这个目标。

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> class A(object):
...   def __init__(self, njobs=1000):
...     self.map = Pool().map
...     self.njobs = njobs
...     self.start()
...   def start(self):
...     self.result = self.map(self.RunProcess, range(self.njobs))
...     return self.result
...   def RunProcess(self, i):
...     return i*i
... 
>>> myA = A()
>>> myA.result[:11]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> myA.njobs = 3
>>> myA.start()  
[0, 1, 4]

Pool内启动__init__是一个奇怪的设计。但是如果你想这样做,你必须得到self.result之类的结果......你可以使用self.start进行后续调用。

在此处获取pathoshttps://github.com/uqfoundation

答案 2 :(得分:0)

实际的解决方法是打破你的课程,例如:像这样:

class A:
    def __init__(self, ...):
        pass

    def compute(self):
        procs = [Process(self.run, ...) for ... in ...]
        [p.start() for p in procs]
        [p.join() for p in procs]

    def run(self, ...):
        pass

pool = A(...)
pool.compute()

当你在__init__内分叉一个进程时,类实例self可能无法完全初始化,因此要求子进程执行self.run是很奇怪的,尽管从技术上讲,是的,它是可能的。

如果不是这样,那么这听起来像是这个问题的一个例子:

http://bugs.python.org/issue11240