24

このトピックに関するいくつかの質問と回答を認識していますが、この特定の問題に対する満足のいく回答は見つかりませんでした:

numpy/scipy関数を介してnumpy配列が操作されるpythonループの単純な共有メモリ並列化を行う最も簡単な方法は何ですか?

私は最も効率的な方法を探しているわけではありません。ループが並列で実行されていない場合に大幅な書き換えを必要としない、実装が簡単なものが欲しかっただけです。OpenMP が低レベル言語で実装するのと同じように。

この点で私が見た最良の答えはthis oneですが、これはループを単一の引数をとる関数に表現する必要があるかなり不格好な方法です.共有配列変換のいくつかの行はcrudを必要とするようです.から並列関数が呼び出され__main__、対話型プロンプト (私が多くの時間を費やす場所) からはうまく機能しないようです。

Python のすべての単純さにより、これは本当にループを並列化する最良の方法ですか? 本当に?これは、OpenMP 方式で並列化するのは簡単なことです。

multiprocessing モジュールの不透明なドキュメントを念入りに読んだところ、単純なループの並列化以外のすべてに適しているように見えるほど一般的であることがわかりました。マネージャー、プロキシ、パイプなどの設定には興味がありません。単純なループがあり、タスク間の通信がない完全に並列です。MPI を使用してこのような単純な状況を並列化するのはやり過ぎのように思えますが、この場合メモリ効率が悪いことは言うまでもありません。

Python 用の多数の異なる共有メモリ並列パッケージについて学ぶ時間がありませんでしたが、誰かがこれについてもっと経験があり、より簡単な方法を教えてくれるかどうか疑問に思っていました。Cython (私は既に使用しています) などのシリアル最適化手法や、BLAS などの並列 numpy/scipy 関数の使用を提案しないでください (私のケースはより一般的で、より並列です)。

4

3 に答える 3

18

Cython並列サポートあり:

# asd.pyx
from cython.parallel cimport prange

import numpy as np

def foo():
    cdef int i, j, n

    x = np.zeros((200, 2000), float)

    n = x.shape[0]
    for i in prange(n, nogil=True):
        with gil:
            for j in range(100):
                x[i,:] = np.cos(x[i,:])

    return x

2コアマシンの場合:

$ cython asd.pyx
$ gcc -fPIC -fopenmp -shared -o asd.so asd.c -I/usr/include/python2.7
$ export OMP_NUM_THREADS=1
$ time python -c 'import asd; asd.foo()'
real    0m1.548s
user    0m1.442s
sys 0m0.061s

$ export OMP_NUM_THREADS=2
$ time python -c 'import asd; asd.foo()'
real    0m0.602s
user    0m0.826s
sys 0m0.075s

np.cos(他のufuncsと同様に)GILをリリースするため、これは並行して正常に実行されます。

これをインタラクティブに使用したい場合:

# asd.pyxbdl
def make_ext(modname, pyxfilename):
    from distutils.extension import Extension
    return Extension(name=modname,
                     sources=[pyxfilename],
                     extra_link_args=['-fopenmp'],
                     extra_compile_args=['-fopenmp'])

および(削除asd.soしてasd.c最初に):

>>> import pyximport
>>> pyximport.install(reload_support=True)
>>> import asd
>>> q1 = asd.foo()
# Go to an editor and change asd.pyx
>>> reload(asd)
>>> q2 = asd.foo()

そうです、場合によっては、スレッドを使用するだけで並列化できます。OpenMPはスレッド化のための単なる豪華なラッパーであるため、Cythonは、構文を簡単にするためにここでのみ必要です。Cythonがなければ、threadingモジュールを使用できます---マルチプロセッシングと同様に(そしておそらくより堅牢に)機能しますが、配列を共有メモリとして宣言するために特別なことをする必要はありません。

ただし、すべての操作でGILが解放されるわけではないため、パフォーマンスのためにYMMVを使用します。

***

そして、他のStackoverflowの回答から削り取られた別のおそらく有用なリンク---マルチプロセッシングへの別のインターフェース:http://packages.python.org/joblib/parallel.html

于 2012-10-26T19:52:48.513 に答える
4

マッピング操作(この場合multiprocessing.Pool.map())を使用することは、多かれ少なかれ、単一のマシンでループを並列化するための標準的な方法です。ビルトインmap()が並列化されない限り、そしてそれまで。

さまざまな可能性の概要については、こちらをご覧ください

openmpはpython (またはcython)で使用できますが、見た目は簡単ではありません。

__main__IIRC、 Windowsとの互換性のために、マルチプロセッシングのものだけを実行する場合のポイントは必需品です。Windowsにはがないためfork()、新しいPythonインタープリターが起動し、コードをインポートする必要があります。

編集

Numpyは、 OpenBLASなどの優れたマルチスレッドBLASライブラリで構成されている場合dot()、、、vdot()などの一部の操作を並列化できます。(この質問も参照してください。)innerproduct()

numpy配列操作はほとんど要素ごとであるため、それらを並列化することは可能のようです。ただし、これには、Pythonオブジェクトの共有メモリセグメントを設定するか、配列を分割してさまざまなプロセスにフィードすることmultiprocessing.Poolが含まれます。どのようなアプローチをとっても、それらすべてを管理するためにメモリと処理のオーバーヘッドが発生します。どのサイズのアレイでこれが実際に努力する価値があるかを確認するには、広範なテストを実行する必要があります。これらのテストの結果は、ハードウェアアーキテクチャ、オペレーティングシステム、およびRAMの量によってかなり異なる可能性があります。

于 2012-10-25T13:03:36.150 に答える