私はPython(Python 3.2を使用)を使用)にまったく慣れておらず、並列化について質問があります。実行したいforループがあります。 Python 3.2:で「マルチプロセッシング」を使用した並列処理
def computation:
global output
for x in range(i,j):
localResult = ... #perform some computation as a function of i and j
output.append(localResult)
合計で、i = 0からj = 100の範囲でこの計算を実行したいと思います。したがって、それぞれが全範囲のサブドメインで関数「計算」を呼び出すいくつかのプロセスを作成したいと思います。これをどのように行うかについてのアイデアはありますか?マルチプロセッシングを使用するよりも良い方法はありますか?
具体的には、領域分割を実行したいのですが、次のコードがあります。
from multiprocessing import Pool
class testModule:
def __init__(self):
self
def computation(self, args):
start, end = args
print('start: ', start, ' end: ', end)
testMod = testModule()
length = 100
np=4
p = Pool(processes=np)
p.map(yes tMod.computation, [(length, startPosition, length//np) for startPosition in range(0, length, length//np)])
PicklingErrorに関するエラーメッセージが表示されます。ここで問題になる可能性のあるアイデアはありますか?
Joblib は、単純な並列ループの目的でマルチプロセッシングをラップアラウンドするように特別に設計されています。マルチプロセッシングに直接取り組む代わりに、それを使用することをお勧めします。
単純なケースは次のようになります。
from joblib import Parallel, delayed
Parallel(n_jobs=2)(delayed(foo)(i**2) for i in range(10)) # n_jobs = number of processes
構文は、理解すれば簡単です。 delayed
を使用して関数foo
を呼び出し、その引数を次の括弧内に含めるジェネレータ構文を使用しています。
あなたの場合、ジェネレーター構文でforループを書き直すか、別の関数(つまり、「worker」関数)を定義して、単一ループ反復の操作を実行し、それをParallel呼び出しのジェネレーター構文に配置する必要があります。
後者の場合、次のようにします。
Parallel(n_jobs=2)(delayed(foo)(parameters) for x in range(i,j))
ここで、foo
は、forループの本体を処理するために定義する関数です。 Parallelはとにかくリストを返すため、リストに追加したくないことに注意してください。
この場合、計算を実行してlocalResult
を取得するための単純な関数を定義することをお勧めします。
_def getLocalResult(args):
""" Do whatever you want in this func.
The point is that it takes x,i,j and
returns localResult
"""
x,i,j = args #unpack args
return doSomething(x,i,j)
_
これで、計算関数で、ワーカーのプールを作成し、ローカルの結果をマップするだけです。
_import multiprocessing
def computation(np=4):
""" np is number of processes to fork """
p = multiprocessing.Pool(np)
output = p.map(getLocalResults, [(x,i,j) for x in range(i,j)] )
return output
_
グローバルは不要なので、ここでは削除しました(通常、グローバルは不要です)。呼び出しルーチンでは、output.extend(computation(np=4))
または同様のことを行う必要があります。
[〜#〜]編集[〜#〜]
コードの「実用的な」例を次に示します。
_from multiprocessing import Pool
def computation(args):
length, startPosition, npoints = args
print(args)
length = 100
np=4
p = Pool(processes=np)
p.map(computation, [(startPosition,startPosition+length//np, length//np) for startPosition in range(0, length, length//np)])
_
関数としてインスタンスメソッドを使用していたため、機能しなかったことに注意してください。マルチプロセッシングは、新しいプロセスを開始し、pickle
を介してプロセス間で情報を送信するため、pickle化できるオブジェクトのみを使用できます。とにかくインスタンスメソッドを使用することは実際には意味がないことに注意してください。各プロセスは親のコピーであるため、プロセスで発生する状態の変更は、とにかく親に伝播されません。