2017-11-27 5 views
0

Ich verwende einen Python-Manager, um Daten zwischen Prozessen zu teilen. Ich wollte meinen Code in kleinere Teile aufteilen und erstellte eine Funktion 'soFactory', die ein Wörterbuch aus Name/Objekt-Paaren aufnehmen und das Objekt unter dem gegebenen Namen beim Manager registrieren würde. Im einfachen Beispiel unten erstelle ich zwei Listen und registriere sie beim Manager. Wenn ich soFactory verwende, gibt der Manager nur eine der Listen zurück (die letzte registriert), egal welchen Namen ich referenziere. Wenn ich die Logik von SoFactory entwirre, bekomme ich Zugriff auf das korrekte Objekt, indem ich ihre registrierten Namen verweise. Ich muss offensichtlich etwas vermissen, aber es nicht sehen.Python-Manager-Register-Problem oder nur mein fehlerhafter Code

# ------------ 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

Danke für die Erklärung, obwohl nicht eingängig macht es Sinn. –

Antwort

1

Es ist eine allgemeine Gefahr Variable Umfang Python, geschieht dies aufgrund der Schließung der lambda erstellt den Namen von Variablen erinnern, aber nicht das Objekt (oder die „Zeiger“). Wenn der lambda aufgerufen wird, wird der Wert t im umgebenden Bereich nachgeschlagen, zu diesem Zeitpunkt ist die Schleife beendet, so t zugeordnet seinen endgültigen Wert von L1, natürlich hängt dies von der Reihenfolge der Rückgabewert dictofSo.items() .

Sie können dies auf Debug-Protokoll von multiprocessing durch wiederum bestätigen:

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

L1 und L2 haben gleiche ID:

[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' 

Wenn Sie die lambda in der Funktion soRoutine() erstellen, da eine Funktion erstellt einen neuen lokalen Bereich, diesmal kann t auf den Wert zeigen, den Sie erwartet haben. Siehe auch .

Verwandte Themen