为什么通过多处理库进行并行编程需要比平时编程更长的时间?

时间:2018-06-13 08:45:16

标签: python parallel-processing multiprocessing

编辑:我更改了立方体函数,而是定义了我注意到这个问题的实际优化问题。我还根据收到的评论改变了块的生成方式。

我正在尝试并行化一些代码以减少计算时间,但执行代码的并行化版本需要比非并行版本更长的时间。我将展示一个简单的例子:

import multiprocessing as mp
import time
import numpy as np
from cvxpy import *
import functools
from sklearn.datasets import load_boston

boston = load_boston()
x = boston.data
y = boston.target

def lm_l_solver(x, y, lambda1):
    n = x.shape[0]
    m = x.shape[1]
    lambda_param = Parameter(sign="positive")
    beta_var = Variable(m)
    lasso_penalization = lambda_param * norm(beta_var, 1)
    lm_penalization = (1/n) * sum_squares(y - x * beta_var)
    objective = Minimize(lm_penalization + lasso_penalization)
    problem = Problem(objective)
    # Solve optimization problem
    beta_sol_matrix = np.zeros((len(lambda1), 1, m))
    for i in range(len(lambda1)):
        lambda_param.value = lambda1[i]
        problem.solve(solver=CVXOPT)
        beta_sol = np.asarray(np.row_stack([b.value for b in beta_var])).flatten()
        beta_sol_matrix[i, :] = beta_sol
    beta_sol_matrix[np.abs(beta_sol_matrix) < 1e-4] = 0
    # Generate response
    response = dict(solution=beta_sol_matrix, lambda1=lambda1)
    return response

if __name__ == '__main__':
    vector = np.arange(1, 100, 1)
    start_time = time.time()
    chunks = np.array_split(vector, mp.cpu_count())
    pool = mp.Pool(processes=mp.cpu_count())
    results = pool.map(functools.partial(lm_l_solver, x, y), chunks)
    pool.close()
    pool.join()
    end_time_1 = time.time()
    results2 = lm_l_solver(x, y, vector)
    end_time_2 = time.time()
    print('Parallel programming took {} seconds'.format(round(end_time_1-start_time, 2)))
    print('Non parallel programming took {} seconds'.format(round(end_time_2 - end_time_1, 2)))

函数lm_l_solver接收数据矩阵x,响应向量y和可能的lambda值向量,并为每个lambda值求解一个惩罚线性模型。

执行这段代码会生成以下输出:

Parallel programming took 5.28 seconds
Non parallel programming took 0.4 seconds

为什么会出现这样的差异? &#34; lm_l_solver&#34;的并行化版本比非并行版本长13倍。我在这里做错了吗?

2 个答案:

答案 0 :(得分:2)

要精确地复制它有点困难,因为它取决于群集的配置。就我而言,无论我使用自己的4核CPU还是小型的24核服务器,并行化行为都不会差很多。

无论如何,罪魁祸首是使用BLAS的求解器CVXOPT已经是多线程的。通过尝试并行化代码,您正在与该线性代数库竞争。 为了证明我的观点,我强迫BLAS仅使用一个线程。在这种情况下,多处理可以显示出一些优势:

$ python solver.py
Parallel programming took 2.0 seconds
Non parallel programming took 2.73 seconds

$ OMP_NUM_THREADS=1 python solver.py
Parallel programming took 0.57 seconds
Non parallel programming took 2.73 seconds

设置OMP_NUM_THREADS = 1基本上会关闭OpenMP多线程,因此您的每个Python进程都保持单线程。 BLAS也使用一个线程。

对于您的应用程序,您必须平衡线程数(具有OMP_NUM_THREADS)和进程数(例如,在mp.Pool(processes=24)中)。

阅读参考书

可重复性

requirements.txt(使用Python 2.7.5):

numpy
cvxpy==0.4.11
sklearn
cvxopt

答案 1 :(得分:0)

多重处理用于CPU绑定功能。 您不能真正对单个过程持续 0.5 秒的任务进行性能比较。您的测试方案需要更新。

与单进程相比,使用多进程时会有很多开销。 Python需要产生新流程,移交任务,传达结果,等等。

Numpy 实际上在幕后执行了外部C代码,这是经过优化的。这意味着它将在单个CPU上非常快速地串行执行。

调度开销支配了您问题中的实际计算时间

您应该增加数据输入,因此Numpy大约需要1-2分钟才能完成一个过程,然后转到多处理过程进行比较。

除此之外,如果顺序不重要,那么如果使用imap_unordered而不是map,则可以在多处理中获得更好的结果。

有一个不错的blogpost,它在多线程和多处理之间进行了一些比较,并且也解决了Numpy操作。我认为您可能会觉得有帮助。