1

マネージャオブジェクトがグローバル変数の場合、非常に奇妙な動作をするmultiprocessing.Managerクラスに問題があります。グローバル変数を使用したMultiprocessing.Manager()の異常な動作

コード1:

import multiprocessing 
from multiprocessing import Manager 

manager = Manager() 

list1 = manager.list(range(4)) 
dict1 = manager.dict({"d":1,"f":2}) 

def process1(list1,dict1): 
    print "process1" 
    dict1["3"] = 123 
    list1.append(10) 

def run(): 
    print "start" 
    global list1 
    global dict1 

    print "list1",list1 
    print "dict1",dict1 

if __name__ == '__main__': 
    print "start" 
    j = multiprocessing.Process(target=process1, args=(list1,dict1)) 
    j.start() 
    j.join() 
    run() 

出力1:

start 
process1 
start 
list1 [0, 1, 2, 3, 10] 
dict1 {'3': 123, 'd': 1, 'f': 2} 

[OK]を、グローバル変数̀list1dict1process1によって変更されていることを意味します。

問題は、list1またはdict1を交換しようとすると機能しません。

コード2:

import multiprocessing 
from multiprocessing import Manager 

manager = Manager() 

list1 = manager.list(range(4)) 
dict1 = manager.dict({"d":1,"f":2}) 

def process1(list1,dict1): 
    print "process1" 
    dict1["3"] = 123 
    list1 = manager.list(range(100,104)) 

def run(): 
    print "start" 
    global list1 
    global dict1 

    print "list1",list1 
    print "dict1",dict1 

if __name__ == '__main__': 
    print "start" 
    j = multiprocessing.Process(target=process1, args=(list1,dict1)) 
    j.start() 
    j.join() 
    run() 

出力2:

start 
process1 
start 
list1 [0, 1, 2, 3] 
dict1 {'3': 123, 'd': 1, 'f': 2} 

ではなく[100, 101, 102, 103]の初期リスト[0, 1, 2, 3]を返す理由を任意のアイデア?

答えて

0

Manager.listオブジェクトはプロセス間で共有されますが、そのオブジェクトにバインドするという名前はバインドされません。すべてのプロセスで同じ名前を使用しても同じです。 globalは、モジュールを実行しているプロセスでモジュール全体で同じバインディングが見られることを意味します(一部のローカルスコープで上書きされない限り)。 multiprocessingがインポートされたという理由だけでは意味がありません;

具体的には、メインプロセスの名前list1はワーカープロセスの名前list1とは関係ありません。それらの唯一の関係は、両方の名前が最初にManager.listという単一の共有インスタンスにバインドされていることです。これは通常、あなたが望むすべてのものです。いずれかのプロセスでlist1という名前を別のオブジェクトにリボディングすると、他のプロセスではlist1という名前のオブジェクトには影響しません。

したがって、2番目の例では、ワーカープロセス内でlist1という名前が新しいmanager.list(range(100,104))インスタンスに(再)バインドされます。これは、メインプロセスでの名前list1のバインドには何の影響も与えません。また、ワーカープロセスが他のプロセスの名前のバインドを変更する可能性もありません。それが起こる可能性があるのであれば、悪夢となります。

共有オブジェクトの値を変更することはできますが、です。しかし、あなたはすでにそれを知っているようです。例えば、

list1[:] = range(100,104) 

を行う代わりに、何のバインディングを変更しませんが、置き換え共有Manager.listインスタンスの全体の内容を(そう名前が同じであるため、主なプロセスは、新しいリストのコンテンツを見るすぎませんが、理由両方の名前が同じオブジェクトにバインドされています)。

ところで、process1の機能では、list1はグローバル名でさえありません。これは関数の引数の1つの名前なので、関数ローカル変数名のように機能します。

短期コース:名前について考えるのをやめ、代わりにオブジェクトのことを考えてください。名前は決してプロセス間で共有されません。

関連する問題