1

我尝试使用多处理模块加速我的 python 程序,但我发现它很慢。一个玩具示例如下:

import time
from multiprocessing import Pool, Manager

class A:
    def __init__(self, i):
        self.i = i

    def score(self, x):
        return self.i - x


class B:
    def __init__(self):
        self.i_list = list(range(1000))
        self.A_list = []

    def run_1(self):
        for i in self.i_list:
            self.x = i
            map(self.compute, self.A_list) #map version
            self.A_list.append(A(i))

    def run_2(self):
        p = Pool()
        for i in self.i_list:
            self.x = i
            p.map(self.compute, self.A_list) #multicore version
            self.A_list.append(A(i))

    def compute(self, some_A):
        return some_A.score(self.x)

if __name__ == "__main__":
    st = time.time()
    foo = B()
    foo.run_1()
    print("Map: ", time.time()-st)
    st = time.time()
    foo = B()
    foo.run_2()
    print("MultiCore: ", time.time()-st) 

我的计算机(Windows 10,Python 3.5)上的结果是

地图:0.0009996891021728516

多核:19.34994912147522

在 Linux 机器(CentOS 7、Python 3.6)上可以观察到类似的结果。

我猜这是由进程之间的对象的酸洗/去皮引起的?我尝试使用 Manager 模块,但未能使其正常工作。

任何帮助将不胜感激。

4

2 回答 2

1

哇,这令人印象深刻(而且很慢!)。

是的,这是因为工作人员必须同时访问对象,这是昂贵的。

所以我玩了一点,并通过将计算方法设为静态来设法获得很多性能。所以基本上,你不再需要共享 B 对象实例了。仍然很慢但更好。

import time
from multiprocessing import Pool, Manager

class A:
    def __init__(self, i):
        self.i = i

    def score(self, x):
        return self.i - x

x=0
def static_compute(some_A):
    res= some_A.score(x)
    return res


class B:
    def __init__(self):
        self.i_list = list(range(1000))
        self.A_list = []

    def run_1(self):
        for i in self.i_list:
            x=i
            map(self.compute, self.A_list) #map version
            self.A_list.append(A(i))

    def run_2(self):
        p = Pool(4)
        for i in self.i_list:
            x=i
            p.map(static_compute, self.A_list) #multicore version
            self.A_list.append(A(i))

对我来说,让它变慢的另一个原因是使用 Pool 的固定成本。您实际上是在启动 Pool.map 1000 次。如果启动这些流程有固定成本,那将使整体战略变慢。也许您应该使用更长的 A_list(比 i_list 更长,这需要不同的算法)来测试它。

于 2018-07-19T09:58:36.980 回答
0

这背后的原因是:

  1. 地图调用由main执行

*意思是当 foo.run_1() 被调用时。主要是为自己映射就像告诉自己该做什么一样。

*当调用 foo_run2() 时,主要是映射该 pc 的最大进程能力。如果您的最大进程是 6,那么主要是映射 6 个线程。就像组织 6 个人告诉你一些事情一样。

旁注:如果您使用:

p.imap(self.compute,self.A_list)

这些项目将按顺序附加到 A_list

于 2018-08-08T21:22:13.480 回答