Python多处理不会产生预期的加速

时间:2014-10-16 08:13:12

标签: python performance python-multiprocessing

我正在尝试使用Python的multiprocessing.Pool模块来优化我的代码,但我没有得到逻辑上期望的加速结果。

我正在做的主要方法涉及计算大量向量和固定大稀疏矩阵的矩阵向量积。下面是一个玩具示例,它执行我需要的,但随机矩阵。

import time
import numpy as np
import scipy.sparse as sp

def calculate(vector, matrix = None):
    for i in range(50):
        v = matrix.dot(vector)
    return v

if __name__ == '__main__':
    N = 1e6
    matrix = sp.rand(N, N, density = 1e-5, format = 'csr')
    t = time.time()
    res = []
    for i in range(10):
        res.append(calculate(np.random.rand(N), matrix = matrix))    
    print time.time() - t

该方法在大约30秒内终止。

现在,由于results的每个元素的计算不依赖于任何其他计算的结果,因此很自然地认为并行计算将加速该过程。我们的想法是创建4个流程,如果每个流程都进行一些计算,那么完成所有流程所需的时间应该会减少4左右的某个因素。为此,我编写了以下代码:

import time
import numpy as np
import scipy.sparse as sp
from multiprocessing import Pool
from functools import partial

def calculate(vector, matrix = None):
    for i in range(50):
        v = matrix.dot(vector)
    return v

if __name__ == '__main__':
    N = 1e6
    matrix = sp.rand(N, N, density = 1e-5, format = 'csr')

    t = time.time()
    input = []
    for i in range(10):
        input.append(np.random.rand(N))
    mp = partial(calculate, matrix = matrix)
    p = Pool(4)
    res = p.map(mp, input)
    print time.time() - t

我的问题是这段代码运行时间略高于20秒,所以我甚至没有将性能提高2倍!更糟糕的是,即使池包含8个进程,性能也不会改进!知道加速没有发生的原因吗?


注意:我的实际方法需要更长时间,输入向量存储在一个文件中。如果我将文件拆分为4件,然后在一个单独的进程中为每个文件手动运行我的脚本,则每个进程的终止速度是整个文件的四倍(如预期的那样)。我很困惑为什么multiprocessing.Pool

没有发生这种加速(显然可能)

Edi :我刚刚发现Multiprocessing.Pool makes Numpy matrix multiplication slower这个问题可能与此有关。不过我必须检查一下。

1 个答案:

答案 0 :(得分:0)

尝试:

p = Pool(4)
for i in range(10):
    input = np.random.rand(N)
    p.apply_async(calculate, args=(input, matrix)) # perform function calculate as new process with arguments input and matrix

p.close()  
p.join() # wait for all processes to complete

我怀疑“部分”对象和地图会导致阻止行为。 (虽然我从来没有使用过部分,所以我不熟悉它。)

“apply_async”(或“map_async”)是特别不阻止的多处理方法 - (参见:Python multiprocessing.Pool: when to use apply, apply_async or map?

通常,对于像这样的“令人尴尬的并行问题”,apply_async对我有用。

编辑:

当我完成时,我倾向于将结果写入MySQL数据库 - 如果不是你的方法,我提供的实现不起作用。如果您想使用列表中的顺序作为跟踪哪个条目的方式,“map”可能是正确的答案,但我仍然怀疑“部分”对象。