web-dev-qa-db-ja.com

numpyをインポートした後、マルチプロセッシングが単一のコアのみを使用するのはなぜですか?

これが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に表示されるものを次に示します。

htop

4コアのラップトップでUbuntu 12.10(3.5.0-26)を実行しています。明らかにjoblib.Parallelは異なるワーカー用に個別のプロセスを生成していますが、これらのプロセスを異なるコア上で実行できる方法はありますか?

118
ali_m

さらにいくつかのグーグル検索の後、私は答えを見つけました here

特定のPythonモジュール(numpyscipytablespandasskimage...)インポート時のコアアフィニティの混乱:私の知る限り、この問題は、特にマルチスレッドOpenBLASライブラリに対するリンクが原因であるようです。

回避策は、次を使用してタスクアフィニティをリセットすることです。

os.system("taskset -p 0xff %d" % os.getpid())

モジュールのインポート後にこの行を貼り付けたため、私の例はすべてのコアで実行されます。

htop_workaround

私のこれまでの経験では、これはnumpyのパフォーマンスに悪影響を与えないように思われますが、これはおそらくマシン固有およびタスク固有です。

更新:

OpenBLAS自体のCPUアフィニティリセット動作を無効にする方法も2つあります。実行時には、環境変数OPENBLAS_MAIN_FREE(またはGOTOBLAS_MAIN_FREE)を使用できます。たとえば、

OPENBLAS_MAIN_FREE=1 python myscript.py

または、ソースからOpenBLASをコンパイルしている場合は、Makefile.ruleを編集して行を含めることにより、ビルド時に永久に無効にすることができます

NO_AFFINITY=1
134
ali_m

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}
26
WoJ
11
NPE