【问题标题】:numpy matrix algebra or python for-loop/list-comprehension automatically utilizes multiprocessing?numpy 矩阵代数或 python for-loop/list-comprehension 自动利用多处理?
【发布时间】:2019-01-29 05:41:38
【问题描述】:

我一直认为 python 列表理解并没有隐含地利用多处理,并且阅读堆栈上的问题(例如this one)也给了我同样的印象。但是,这是我的小实验:

import numpy as np
import time

# some arbitrary data
n = 1000
p = 5
X = np.block([[np.eye(p)], [np.zeros((n-p, p))]])
y = np.sum(X, axis=1) + np.random.normal(0, 1, (n, ))
n_loop = 100000

# run linear regression using direct matrix algebra
def in_sample_error_algebra(X, y):
    beta_hat = np.linalg.inv(X.transpose()@X)@(X.transpose()@y)
    y_hat = X@beta_hat
    error = metrics.mean_squared_error(y, y_hat)
    return error


start = time.time()
errors = [in_sample_error_algebra(X, y) for _ in range(n_loop)]
print('run time =', round(time.time() - start, 2), 'seconds')

运行时间 = 19.68 秒

当这段代码运行时,我的 CPU 的所有 6 个(物理)内核都达到了 100%

更神奇的是,当我从列表推导式更改为 for 循环时,同样的事情发生了。我认为使用.append,必须按顺序完成。见下文:

start = time.time()
errors = []
for _ in range(n_loop):
    errors.append(in_sample_error_algebra(X, y))
print('run time =', round(time.time() - start, 2), 'seconds')

运行时间 = 21.29 秒

有什么理论吗?

Python 3.7.2, numpy 1.15.4

【问题讨论】:

  • 我很确定那是 numpy 使用线程...
  • 多线程甚至可以帮助python中的CPU绑定程序吗?我以为有 GIL。
  • 许多 numpy 计算不受 GIL、IIRC 的约束。
  • numpy c 代码的各个块都有 no gil 包装器。

标签: python-3.x numpy parallel-processing python-3.7


【解决方案1】:

确实,纯 Python 计算并不能从 多线程 中受益。 global interpreter lock (GIL) 防止多个线程同时访问解释器。

然而,multiprocessing 在 Python 中是可能的,因为每个进程都运行自己的 Python 解释器实例。这有性能成本:进程之间的初始化和数据共享不是免费的。通常甚至不值得付出努力。

numpy 的故事不同。 Numpy 主要由用 C 编写的本机函数组成。当 C 代码暂时不需要解释器时,它可以释放 GIL 并允许同时运行不同的 Python 线程。 C 代码还可以生成“非 Python”线程来并行计算。这就是 numpy 中发生的事情。

实际上,numpy 本身不会产生线程(我认为),但许多矩阵/向量和线性代数例程调用低级库 BLAS 和 LAPACK。这些库存在各种实现,其中一些针对多线程进行了优化。您的 numpy 版本显然使用了其中之一。

总之,外部列表推导和for 循环都不是并行运行的,但np.linalg.inv 和矩阵乘积X @ beta_hat 可以在内部运行多个线程。请参阅Parallel Programming with numpy and scipy 了解更多信息。

【讨论】:

  • 感谢您的精彩解释!似乎 numpy 是否使用了我机器的多个核心不是在“架构师时间”确定的,这取决于 numpy 的版本,以及可以使用哪些功能(比如 inv 或 @ vs simple + - )。如果我想以通用方式设计我的代码,那就是一个问题——如果我提供一个允许并行化某些虚函数的接口,我不知道其他人是否会实现调用已经并行化的函数。如果是,那么性能将是灾难性的(我测试过)。在这种情况下有什么好的做法吗?
  • 更糟糕的是,它不仅依赖于 numpy 版本,而且同一版本可以链接到不同的计算后端。如果您提供函数,则使并行化成为可选功能并警告用户明智;)您可以尝试在 numpy 中禁用多线程(从这里开始:Python: How do you stop numpy from multithreading?),但我不知道它的可移植性或鲁棒性如何。跨度>
  • 如果不是我的本地计算机,而是我的可选腭化功能仅对用户开放,以使用由多台机器组成的远程集群,你会说这个问题得到了缓解吗?我在想 AWS,一旦我把我的 n 个工作扔给它,它就不会像我对本地单台机器做同样的事情一样落入同样的陷阱,不是吗?
  • 我在集群方面的经验非常有限。如果每台机器只有一个活动作业,那应该没问题。我过去看到 numpy 最多使用 8 或 16 个内核左右,但那是几年前的事了,我不确定它是否真的对你的情况有用......
  • 非常感谢,这应该是一个单独的问题。也许在我先在 AWS 上试用之后。
猜你喜欢
  • 2023-02-17
  • 2019-09-24
  • 2017-09-12
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 2019-03-13
相关资源
最近更新 更多