2012-06-01 4 views
10

Ich fange an, mit den IPython parallelen Tools zu experimentieren und ein Problem haben. Ich starte meine Python-Motoren mit:Python Namespace Probleme mit Ipython parallel

ipcluster start -n 3 

dann der folgende Code läuft gut:

from IPython.parallel import Client 

def dop(x): 
    rc = Client() 
    dview = rc[:] 
    dview.block=True 
    dview.execute('a = 5') 
    dview['b'] = 10 
    ack = dview.apply(lambda x: a+b+x, x) 
    return ack 

ack = dop(27) 
print ack 

returns [42, 42, 42], wie es sollte. Aber wenn ich den Code in verschiedenen Dateien zu brechen: dop.py:

from IPython.parallel import Client 

def dop(x): 
    rc = Client() 
    dview = rc[:] 
    dview.block=True 
    dview.execute('a = 5') 
    dview['b'] = 10 
    print dview['a'] 
    ack = dview.apply(lambda x: a+b+x, x) 
    return ack 

und versuchen Sie Folgendes:

from dop import dop 
ack = dop(27) 
print ack 

bekomme ich Fehler von jedem Motor:

[0:apply]: NameError: global name 'a' is not defined 
[1:apply]: NameError: global name 'a' is not defined 
[2:apply]: NameError: global name 'a' is not defined 

I don verstehe es nicht ... warum kann ich die Funktion nicht in eine andere Datei einfügen und importieren?

Antwort

16

Schnell Antwort: dekorieren Sie Ihre Funktion mit @interactive von IPython.parallel.util [1], wenn Sie es Zugriff haben wollen auf den globalen Namensraum des Motors:

 
from IPython.parallel.util import interactive 
f = interactive(lambda x: a+b+x) 
ack = dview.apply(f, x) 

Die tatsächliche Erklärung:

der IPython Benutzernamespace im Wesentlichen das Modul __main__. Dies ist, wo Code ausgeführt wird, wenn Sie execute('a = 5') tun.

Wenn Sie eine Funktion interaktiv zu definieren, ist sein Modul auch __main__:

 
lam = lambda x: a+b+x 
lam.__module__ 
'__main__' 

Wenn der Motor unserializes eine Funktion, tut sie dies in den entsprechenden globalen Namensraum für die Funktion des Moduls, so Funktionen in __main__ definiert in Ihre Kunden sind auch in __main__ auf der Engine definiert und haben somit Zugriff auf a.

Sobald Sie es in einer Datei speichern, und importieren, dann werden die Funktionen nicht mehr an __main__, aber das Modul dop:

 
from dop import dop 
dop.__module__ 
'dop' 

Alle Funktionen konventionell in diesem Modul definiert (Lambda-Ausdrücke enthalten) haben Dieser Wert, also wenn sie auf der Engine ausgepackt werden, ist ihr globaler Namespace der des dop Moduls, nicht__main__, so dass Ihr "a" nicht zugänglich ist.

Aus diesem Grund stellt IPython einen einfachen @interactive Dekorator bereit, der dazu führt, dass jede Funktion so entpackt wird, als wäre sie in __main__ definiert, unabhängig davon, wo die Funktion tatsächlich definiert ist.

Ein Beispiel für den Unterschied, nehmen diese dop.py:

 
from IPython.parallel import Client 
from IPython.parallel.util import interactive 

a = 1 

def dop(x): 
    rc = Client() 
    dview = rc[:] 
    dview['a'] = 5 
    f = lambda x: a+x 
    return dview.apply_sync(f, x) 

def idop(x): 
    rc = Client() 
    dview = rc[:] 
    dview['a'] = 5 
    f = interactive(lambda x: a+x) 
    return dview.apply_sync(f, x) 

Nun wird dop verwenden 'a' aus dem dop-Modul und idop wird 'a' aus Ihrem Motor Namespaces.Der einzige Unterschied zwischen den beiden ist, dass die Funktion in @interactive gewickelt anzuwenden geben wird:

 
from dop import dop, idop 
print dop(5) # 6 
print idop(5) # 10 

[1]: In IPython> = 0,13 (bevorstehende Veröffentlichung), @interactive auch als from IPython.parallel import interactive zur Verfügung steht, wo es sollte immer gewesen sein.