これがOSの問題としてカウントされるかどうかはわかりませんが、Python事の終わり。
CPU負荷の高いfor
ループをjoblib
を使用して並列化しようとしましたが、各ワーカープロセスが異なるコアに割り当てられるのではなく、すべてのプロセスが同じコアに割り当てられ、パフォーマンスは向上しません。
これは非常に簡単な例です...
from joblib import Parallel,delayed
import numpy as np
def testfunc(data):
# some very boneheaded CPU work
for nn in xrange(1000):
for ii in data[0,:]:
for jj in data[1,:]:
ii*jj
def run(niter=10):
data = (np.random.randn(2,100) for ii in xrange(niter))
pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all')
results = pool(delayed(testfunc)(dd) for dd in data)
if __== '__main__':
run()
...そして、このスクリプトの実行中にhtop
に表示されるものを次に示します。
4コアのラップトップでUbuntu 12.10(3.5.0-26)を実行しています。明らかにjoblib.Parallel
は異なるワーカー用に個別のプロセスを生成していますが、これらのプロセスを異なるコア上で実行できる方法はありますか?
さらにいくつかのグーグル検索の後、私は答えを見つけました here 。
特定のPythonモジュール(numpy
、scipy
、tables
、pandas
、skimage
...)インポート時のコアアフィニティの混乱:私の知る限り、この問題は、特にマルチスレッドOpenBLASライブラリに対するリンクが原因であるようです。
回避策は、次を使用してタスクアフィニティをリセットすることです。
os.system("taskset -p 0xff %d" % os.getpid())
モジュールのインポート後にこの行を貼り付けたため、私の例はすべてのコアで実行されます。
私のこれまでの経験では、これはnumpy
のパフォーマンスに悪影響を与えないように思われますが、これはおそらくマシン固有およびタスク固有です。
OpenBLAS自体のCPUアフィニティリセット動作を無効にする方法も2つあります。実行時には、環境変数OPENBLAS_MAIN_FREE
(またはGOTOBLAS_MAIN_FREE
)を使用できます。たとえば、
OPENBLAS_MAIN_FREE=1 python myscript.py
または、ソースからOpenBLASをコンパイルしている場合は、Makefile.rule
を編集して行を含めることにより、ビルド時に永久に無効にすることができます
NO_AFFINITY=1
Python 3は、アフィニティを直接設定するために methods を公開するようになりました
>>> import os
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
>>> os.sched_setaffinity(0, {1, 3})
>>> os.sched_getaffinity(0)
{1, 3}
>>> x = {i for i in range(10)}
>>> x
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> os.sched_setaffinity(0, x)
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
これは、UbuntuでPythonを使用する場合の一般的な問題であり、joblib
に固有のものではありません。
CPUアフィニティ( taskset
)を試すことをお勧めします。