注意:仔细阅读这个问题。我知道 CPython 有 GIL。对于大多数功能,Numpy 通常不受 GIL 限制。
更新:事实证明这与此问题中描述的问题相同。如果您将 numpy 与 OpenBLAS 链接,它会在您导入 numpy 后立即设置整个进程的 CPU 亲和性。这可以通过 OpenBLAS 构建的标志来修复。
我的应用程序使用 numpy,它是我从源代码构建的(即没有easy_install
等)。通常,我的自定义构建工作得很好。不过最近,我做了一些事情(对我的构建?对我的操作系统?)阻止 numpy 使用多个 CPU 内核。
考虑这个简单的程序,它执行以下操作:
- 在工作线程中运行一个愚蠢的工作负载。
- 在两个并行线程中再次运行相同的工作负载两次。
在正常工作的 numpy 安装中,第二(并行)步骤几乎与第一步一样快。但是在我的特殊版本中,第二步需要两倍的时间!仅使用 1 个 CPU。它表现得好像numpy.sqrt
没有释放 GIL,但我知道它应该。
伙计,即使我想,我也不知道如何打破这样的 numpy 构建。它拒绝使用超过 1 个 CPU 内核!我是怎么做到的?我如何解决它?
编辑:更多细节:numpy-1.7.0、gcc、Linux(Fedora 16),但我认为这些细节不太重要。我之前用这个配置构建过,没有遇到这个问题。我想我想知道是否有特定的操作系统或 python 设置会导致这样的行为。
import numpy, threading, time
a1 = numpy.random.random((500,500,200)).astype(numpy.float32)
a2 = numpy.random.random((500,500,200)).astype(numpy.float32)
a3 = numpy.random.random((500,500,200)).astype(numpy.float32)
def numpy_workload(name, a):
print "starting numpy_workload " + name
for _ in range(10):
numpy.sqrt(a)
print "finished numpy_workload " + name
t1 = threading.Thread(target=lambda: numpy_workload("1", a1))
t2 = threading.Thread(target=lambda: numpy_workload("2", a2))
t3 = threading.Thread(target=lambda: numpy_workload("3", a3))
start = time.time()
t1.start()
t1.join()
stop = time.time()
print "Single thread done after {} seconds\n".format( stop - start )
start = time.time()
t2.start()
t3.start()
t2.join()
t3.join()
stop = time.time()
print "Two threads done after {} seconds\n".format( stop - start )