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


127

これがOSの問題としてそれ以上に数えられるかどうかはわかりませんが、誰かがPythonの終わりから何らかの洞察を持っている場合に備えて、ここで尋ねると思いました。

for使用してCPU負荷の高いループを並列化しようとしましたが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 __name__ == '__main__':
    run()

...そしてhtop、このスクリプトの実行中に表示される内容は次のとおりです。

htop

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


stackoverflow.com/questions/15168014/…-回答はありませんが、残念ながら同じ問題のようです。
NPE 2013年



これはまだ問題ですか?私はこれをPython 3.7で再作成し、numpyをmultiprocessing.Pool()でインポートしようとしていますが、すべてのスレッドを使用しています(必要に応じて)。これが修正されたことを確認したいだけです。
Jared Nielsen

回答:


148

もう少しグーグルで調べた後、私はここで答えを見つけました。

これは、その特定の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

ありがとう、あなたの解決策は問題を解決しました。1つの質問、私は同じコードを持っていますが、異なる2台のマシンで異なる方法で実行します。どちらのマシンもUbuntu 12.04 LTS、python 2.7ですが、この問題が発生するのは1台だけです。なぜかわかりますか?
iampat 2013年

どちらのマシンにもOpenBLAS(OpenMPIでビルド)があります。
iampat 2013年

2
古いスレッドですが、他の誰かがこの問題を見つけた場合に備えて、私には正確な問題があり、それは実際にOpenBLASライブラリに関連していました。考えられる2つの回避策と関連する議論については、こちらを参照してください。
ガブリエル

2
CPUアフィニティを設定するもう1つの方法は、を使用することpsutilです。
イオアニスフィリッピディス2016

2
Pythonのバージョンが違いになるだろう、なぜ私はいかなる理由を見ることができないので、@JHGそれは、むしろPythonのよりOpenBLASの問題だ
ali_m

27

Python 3は、親和性を直接設定するメソッドを公開するようになりました

>>> 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}

1
エラー> AttributeError:モジュール 'os'に属性 'sched_getaffinity'がありません、Python 3.6
Paddy

4
@Paddyリンクされたドキュメントから:一部のUnixプラットフォームでのみ使用できます。
BlackJack

2
私は同じ問題を抱えているが、私はトップos.system(「タスクセット-p 0xffの%D」%のos.getpid())で、これと同じ行を統合するが、そのすべてのCPUを使用していない
rajeshcis

12

これは、Ubuntu上のPythonに共通する問題であるようであり、以下に固有のものではありませんjoblib

CPUアフィニティを試すことをお勧めします(taskset)。


Python on Ubuntuこれは、Windowsや他のOSで問題なく動作していることを意味します。それは...ですか?
マスト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.