2012-06-01 24 views
10

Estoy empezando a experimentar con las herramientas paralelas de IPython y tengo un problema. Empiezo mis motores de pitón con:Problemas de espacio de nombres de Python con ipython parallel

ipcluster start -n 3 

continuación, el código siguiente funciona bien:

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 

vuelve [42, 42, 42] como debería. Pero si rompo el código en archivos diferentes: 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 

y aplica los siguientes:

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

recibo errores de cada 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 

Pongo Lo entiendo ... ¿por qué no puedo poner la función en un archivo diferente e importarlo?

Respuesta

16

respuesta rápida: la decoración de su función con @interactive de IPython.parallel.util [1] si desea que tenga acceso al espacio de nombres global del motor:

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

La explicación real:

el usuario del espacio de nombres IPython es esencialmente el módulo __main__. Aquí es donde se ejecuta el código cuando lo haces execute('a = 5').

Si se define una función interactiva, su módulo es también __main__:

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

Cuando el motor unserializes una función, lo hace en el espacio de nombres global adecuado para el módulo de la función, por lo que las funciones definidas en __main__ en su cliente también se define en __main__ en el motor y, por lo tanto, tiene acceso al a.

Una vez que pones en un archivo y lo importa, entonces las funciones ya no están unidos a __main__, pero el módulo dop:

 
from dop import dop 
dop.__module__ 
'dop' 

Todas las funciones convencionalmente definidos en el módulo (lambdas incluidos) tendrá este valor, por lo tanto, cuando se desempaquetarán en el motor, su espacio de nombre global será el del módulo dop, , no__main__, por lo que no se podrá acceder a su 'a'.

Por este motivo, IPython proporciona un simple decorador @interactive que da como resultado que cualquier función se desempaquete como si estuviera definida en __main__, independientemente de dónde esté realmente definida la función.

Para un ejemplo de la diferencia, tome este 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) 

Ahora, dop utilizará 'a' del módulo de DOP, y idop utilizará 'a' de los espacios de nombres del motor.La única diferencia entre los dos es que la función pasa a aplicar se envuelve en @interactive:

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

[1]: En IPython> = 0,13 (próximo lanzamiento), @interactive también está disponible como from IPython.parallel import interactive, donde siempre debe Ha estado.

Cuestiones relacionadas