我知道大多数numpy操作都会释放GIL。因此,当使用python的多线程时,大多数操作都可以获得预期的速度提升。但我发现奇怪的是,numpy.linalg.inv
的情况并非如此。
实验
我尝试了以下方法
import numpy as np
import time
from concurrent.futures import ThreadPoolExecutor
def numpy_op(arr):
# do matrix inversion here
return np.linalg.inv(arr)
num_workers = 8
np.random.seed(42)
args = [np.random.randn(10000, 10000) for _ in range(num_workers)]
# parallelize with thread pool
s_time = time.time()
with ThreadPoolExecutor(max_workers=num_workers) as executor:
res = list(executor.map(numpy_op, args))
# sequential code
res = []
for arg in args:
res.append(numpy_op(arg))
print(f'time consumed: {time.time()-s_time:.2f}s')
字符串
结果
- 多线程:36.44秒
- 连续:28.14s
然而,如果我做一些除了矩阵求逆之外的其他numpy操作,例如
def numpy_op(arr):
# some random numpy operations here
return (arr**2 + 2) ** 0.5
型
通过这些操作,结果是
- 多线程:0.62s
- 连续:3.71秒
版本
我正在使用Python 3.9.10
和numpy 1.24.3
1条答案
按热度按时间2ic8powd1#
这里的问题是
np.linalg.inv
的实现本身是多线程的。要查看此效果,请在示例的顶部添加以下行:字符串
这将可用于此类操作的线程数量减少到只有一个(假设您的numpy是使用openBLAS构建的。其他情况请参见threadpoolctl)。
在我的机器上,这个变化翻转了结果:
我不知道numpy中是否有一个多线程操作的完整列表,但在优化多核吞吐量时,这是需要考虑的。