2017-11-27 10 views
0

私はプロセス間でデータを共有するためにpythonマネージャーを使用します。私は自分のコードを小さな断片に分割し、名前/オブジェクトの対の辞書を取り、与えられた名前でマネージャにオブジェクトを登録する関数 'soFactory'を作成しました。 以下の簡単な例では、2つのリストを作成し、マネージャーに登録します。 soFactoryを使用すると、マネージャは、参照する名前に関係なく、リストのうちの1つ(最後に登録されたもの)のみを返します。 soFactoryのロジックを解明すれば、登録された名前を参照して正しいオブジェクトにアクセスできます。 私はそれを見ていないが明白なものを見逃しているに違いありません。pythonマネージャーの問題の登録または私の間違ったコード

# ------------ prototype for SO question ------- 
from sys import stderr 

def soFactory(dictofSo, manager): 
    """shared object factory""" 
    for n,t in dictofSo.items(): 
     print >>stderr, 'created item',n,t 
     manager.register(n, callable=lambda: t) 

def soRoutine(n, t, manager): 
    manager.register(n, callable=lambda: t) 

def test_soFactory(useFactory=True): 
    """tests the soFactory function""" 
    from multiprocessing import managers 
    m = managers.BaseManager(address='/var/tmp/tqps-test', authkey='abc123') 
    mySOlist = {'L1': [1],'L2':[2]} 

    if useFactory: 
     soFactory(mySOlist, m) 
    else: 
     for n, t in mySOlist.items(): 
      soRoutine(n, t, m) 

    m.start() 

    m.L1().append('only in L1!') 
    print >>stderr, m.L1(), m.L2() 

>>> test_soFactory() 
created item L2 [2] 
created item L1 [1] 
[1, 'only in L1!'] [1, 'only in L1!'] 

>>> test_soFactory(useFactory=False) 
[1, 'only in L1!'] [2] 
>>> 
+0

説明のためにありがとうが、直感的ではありませんが、意味があります。 –

答えて

1

これは原因作成lambdaは変数の名前ではなく、オブジェクト(または「ポインタ」)を覚えて閉鎖に起こる、共通のpython変数のスコープの落とし穴です。 lambdaが呼び出されるとの値が周囲のスコープで参照され、その時点でループが終了したので、tに最終値L1を割り当てます。これは戻り値の順番によって異なります。dictofSo.items()

あなたはmultiprocessingのデバッグログを有効にすることによって、これを確認することができます:

import logging 
import multiprocessing 
multiprocessing.util.log_to_stderr(logging.DEBUG) 

L1L2同じid持っている:あなたは機能soRoutine()lambdaを作成するときに機能するので、

[DEBUG/MainProcess] requesting creation of a shared 'L1' object 
[DEBUG/BaseManager-1] 'L1' callable returned object with id '104aef878' 
[DEBUG/MainProcess] INCREF '104aef878' 
... 
[DEBUG/MainProcess] requesting creation of a shared 'L2' object 
[DEBUG/BaseManager-1] 'L2' callable returned object with id '104aef878' 

を新しいローカルスコープを作成しますが、今回はtが期待した値を指すことができます。 this postも参照してください。

関連する問題