4

複数のプロセスを経て 1 つの共通辞書を更新しようとしています。このコードの問題点を教えてください。次の出力が得られます。

inside function
{1: 1, 2: -1}
comes here
inside function
{1: 0, 2: 2}
comes here
{1: 0, 2: -1}

ありがとう。

from multiprocessing import Lock, Process, Manager

l= Lock()


def computeCopyNum(test,val):
    l.acquire()
    test[val]=val
    print "inside function"
    print test
    l.release()
    return

a=dict({1: 0, 2: -1})

procs=list()

for i in range(1,3):
    p = Process(target=computeCopyNum, args=(a,i))
    procs.append(p)
    p.start()

for p in procs:
p.join()
    print "comes here"

print a
4

3 に答える 3

9

答えは実に簡単です。複数の異なる python プロセスを開始する multiprocessing モジュールを使用しています。プロセスごとに異なるアドレス空間があり、メモリを共有しないため、すべてのプロセスがディクショナリの独自のローカル コピーに書き込みます。

マルチプロセッシング モジュールを使用してプロセス間通信を行う最も簡単な方法は、キューを使用してスレーブ プロセスとマスター プロセス間で通信することです。

from multiprocessing import Process, Queue

def computeCopyNum(queue, val):
    queue.put(val) # can also put a tuple of thread-id and value if we would like to

procs=list()

queue = Queue()
for i in range(1,3):
    p = Process(target=computeCopyNum, args=(queue, i))
    procs.append(p)
    p.start()

for _ in procs:
    val = queue.get()
    # do whatever with val

for p in procs:
    p.join()

各スレーブプロセスが複数の出力値を生成できる場合は、各スレーブプロセスがセンチネル値をキューに書き込んで、マスターに完了したことを通知するのが賢明かもしれません。次に、コードは次のようになります。

def slave(queue):
    for i in range(128): # just for example
        val = #some calculated result
        queue.put(val)

    queue.put(None) # add a sentinel value to tell the master we're done

queue = Queue()

# spawn 32 slave processes
num_procs = 32
procs = [Process(target=slave, args=(queue, )) for _ in range(num_procs)]
for proc in procs: 
    proc.start()

finished = 0
while finished < num_procs:
    item = queue.get()
    if item is None: 
        finished += 1
    else: 
        # do something with item

for proc in procs: 
    proc.join()

別の回答に示されているように、マネージャーを使用することもできます。このアプローチの問題点は、プロセスのアドレス空間間で多くの暗黙的なメモリ コピーが発生する可能性があり、それを判断するのが難しいことです。私は常に明示的なキューを使用することを好みます。

于 2012-09-21T21:56:29.217 に答える
5

をインポートManagerしますが、何もしません。最初のアプローチとして、代わりにこれを行います。

a = Manager().dict({1: 0, 2: -1})

を使用すると、グローバル変数が期待どおりに機能しませんmultiprocessing。サブプロセスはコピーにのみアクセスでき、プロセス間で情報を伝達できる特別に設計されたオブジェクトを使用していない限り、サブプロセスが行った変更は終了時に忘れられます。

プロセス間でデータを渡すにはさまざまな方法がありますが、Manager通常は上記のようにオブジェクトを使用するのが最も簡単です。Managerオブジェクトを使用して、複数の共有オブジェクトを作成することもできます。

manager = Manager()
a = manager.dict({1: 0, 2: -1})
b = manager.list((1, 2, 3))

詳細については、Managerドキュメントを参照してください。

また、お使いのロックも不要です。がそれManagerを処理します。ドキュメントが言うように、

一般に、同期プリミティブは、マルチスレッド プログラムほど必要ではありません。

于 2012-09-21T21:40:05.050 に答える
0

プロセスは、スレッドのようにメモリを共有しません。各プロセスは、最終的に a の独自の独立したコピーになります。異なるスレッドで作業を行いたい場合は、パイプまたはその他のプロセス間通信を使用して、データを中央プロセスに戻す必要があります。

于 2012-09-21T21:39:53.687 に答える