我正在努力提高我的一些代码的性能,首先根据两个索引构造一个4x4矩阵,对齐此矩阵,然后将每个矩阵的每个对角化的特征向量存储在一个4维数组中。目前,我只是串行浏览所有索引,然后将特征向量存储在4维数组中。现在,我想知道是否可以通过使用线程或类似的东西来平行化这一点,使得每个线程将对角化一个矩阵然后将其存储在其位置。我遇到的问题是,这样做有什么限制?当不同的线程想要写入生成的4-dim时,我会遇到问题。在同一个数组,我是否必须使用锁以防止这种情况?我很抱歉,如果这个问题很简单,但通过搜索,我无法找到任何相关内容,而且我对线程的了解非常有限。最小的例子是
from numpy.linalg import eigh as eigh2
from scipy import *
spectrum = zeros([L//2,L//2,4,4],complex)
for i in range(0,L//2):
for j in range(0,L//2):
k = [-(2 * i*2*pi/L),-(2 * j*2*pi/L)]
H = ones([4,4],complex)
energies, states = eigh2(H)
spectrum[i,j,:,:] = states
请注意,为了简洁,我已经交换了依赖于k构造矩阵的函数,用于某些常数矩阵。
我真的很感激任何帮助或指向资源如何实现一些并行化。线程是一种提高性能的现实方法吗?
答案 0 :(得分:2)
简而言之,是的,您可能需要锁定 - 但如果您可以重新组织您的问题,那可能比锁定要好得多。
答案很长,特别是因为我不知道你已经知道多少。
一般来说,线程在CPython中对CPU绑定代码没有太大帮助,因为Global Interpreter Lock会阻止任何线程解释Python的一行(实际上是字节码),如果另一个线程在这样做的中间。但是,NumPy具有在某些地方专门发布GIL以允许线程更好地工作的代码,因此如果你在低级别NumPy算法中使用CPU绑定,实际上的线程可以工作。文档并不总是清楚哪些函数执行此操作,哪些函数不执行,因此您可能必须自己测试它,以确定并行化是否有用。 (执行此操作的快速和肮脏的方法是破解您的代码版本,只执行计算而不将它们存储在任何位置,跨N个线程运行它,并查看在执行此操作时有多少内核忙。)
现在,一般来说,在CPython中,围绕某些类型的操作不需要锁定,包括简单类型的__setitem__
- 但这是因为相同的GIL,所以它不会在这里帮助你。如果你有多个操作都试图写入同一个数组,他们将需要锁定该数组。
但是可能有更好的解决方法。如果您能找到一种方法将数组划分为更小的数组,在任何给定时间只修改其中一个数组,则不需要任何锁定。或者,如果您可以让线程返回较小的数组,这些数组可以由单个主线程组装到最终答案中,而不是首先在原地工作,那也可以。
但是在你这样做之前......在某些情况下,NumPy(或者更确切地说,它正在使用的库之一)已经为你自动并行化,或者如果你以不同方式构建它。或者它可能是SIMD矢量化的东西,实际上比线程提供更多的加速,你可能最终破坏。等等。
因此,在尝试任何操作之前,请确保已安装了所有可选先决条件的经过适当优化的NumPy。然后确保它只使用一个核心。然后构建一个测试脚手架,以便比较不同的实现。然后你可以试试你可以提出的每个基于锁定,非共享和非变异的算法,看看并行性是否比额外的东西更有帮助。