python - 为什么通过多处理库进行并行编程比通常的编程需要更长的时间?
问题描述
编辑:我更改了三次函数并定义了我注意到这个问题的实际优化问题。我还根据收到的评论更改了生成块的方式。
我正在尝试并行化一些代码以减少计算时间,但执行代码的并行化版本比非并行化版本花费更长的时间。我将展示一个简单的例子:
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
为什么会有这样的差异?“lm_l_solver”的并行版本比非并行版本花费了 13 倍的时间。我在这里做错了吗?
解决方案
精确复制有点困难,因为它取决于集群的配置。就我而言,无论我使用自己的 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
推荐阅读
- javascript - 如何使用 jquery 保持两个过滤器处于活动状态?
- python - pytest 中的 tmpdir 是否仅在我们写入文件时才创建文件?
- java - GridView setOnItemClickListener 更改项目背景颜色,删除所有其他项目的背景颜色
- spring - 将 Spring bean 范围从请求更改为单例的影响
- c# - 使用 aspnet 身份的附加验证
- javascript - 为什么 (4 + 5 + "6") 是 96 而 ("4" + 5 + 6) 在 Javascript 上是 456?
- c - 在 C 中读取具有特定格式的文本文件
- c# - 类型 Microsoft.AspNet.Identity.PasswordHasher 未定义
- c# - 如何使用 EF Core 正确更新表中的列表数据
- apache-spark - 如何在 Kafka 集群上运行 Apache Spark 批处理作业?