注:この質問をよく読んでください。CPython には GIL があることを理解しています。Numpy は通常、ほとんどの機能について GIL によって制限されません。
更新:これは、この質問で説明されている問題と同じであることが判明しました。OpenBLAS に対して numpy をリンクすると、numpy をインポートするとすぐにプロセス全体の CPU アフィニティが設定されます。これは、OpenBLAS ビルドのフラグで修正できます。
私のアプリは、ソースからビルドした numpy を使用しています (つまりeasy_install
、 なしなど)。通常、私のカスタム ビルドは問題なく動作します。最近ですが、numpy が複数の CPU コアを使用できないようにする (ビルドに対して? OS に対して?) 何かを行いました。
次のことを行うこの単純なプログラムについて考えてみましょう。
- ワーカー スレッドでばかげたワークロードを実行します。
- 2 つの並列スレッドで同じワークロードをさらに 2 回実行します。
適切に動作する numpy インストールでは、2 番目の (並行) ステップは最初のステップとほぼ同じ速さです。しかし、私の特別なビルドでは、2 番目のステップに 2 倍の時間がかかります。使用する CPU は 1 つだけです。numpy.sqrt
GIL を解放しないかのように動作していますが、そうすべきであることはわかっています。
男、私が望んでいたとしても、このような派手なビルドを壊す方法がわかりません。複数の CPU コアを使用することを拒否します。どうやってこれをしたのですか?どうすれば修正できますか?
編集:詳細:numpy-1.7.0、gcc、Linux(Fedora 16)ですが、これらの詳細はあまり重要ではないと思います。この問題に遭遇することなく、以前にこの構成で構築しました。このような動作を引き起こす可能性のある特定の OS または 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 )