2011-11-17 15 views
10

Esto es tan roto, espero que eres misericordioso conmigo:¿Cómo combinar callLater y addCallback?

reactor.callLater(0, myFunction, parameter1).addCallback(reactor.stop) 
reactor.run() 

myFunction devuelve un diferido.

espero que sea claro lo que quiero hacer:

  • tan pronto como el reactor está en funcionamiento, quiero llamar myFunction. Es por eso que estoy usando 0 como el parámetro de retraso. ¿No hay otra manera que llamar a CallLater? Parece divertido pasar un retraso de 0.
  • Quiero detener el reactor tan pronto como myFunction ha completado la tarea.

Los problemas que tengo hasta ahora:

  • AttributeError: DelayedCall instance has no attribute 'addCallback'. ¡Lo suficientemente justo! ¿Cómo coloco una devolución de llamada en la cadena de devolución de llamada iniciada por myFunction?
  • exceptions.TypeError: stop() takes exactly 1 argument (2 given).

Para resolver el segundo problema tuviera que definir una función especial:

def stopReactor(result): 
    gd.log.info('Result: %s' % result) 
    gd.log.info('Stopping reactor immediatelly') 
    reactor.stop() 

y cambiar el código para:

reactor.callLater(0, myFunction, parameter1).addCallback(stopReactor) 
reactor.run() 

(aún no funciona debido al problema callLater, pero stopReactor funcionará ahora)

¿No hay realmente otra manera de llamar a reactor.stop excepto por de multando una función extra?

Respuesta

19

IReactorTime.callLater y Deferred se mezclaron entre sí por twisted.internet.task.deferLater.

from twisted.internet import reactor, task 

d = task.deferLater(reactor, 0, myFunction, parameter1) 
d.addCallback(lambda _: reactor.stop()) 
reactor.run() 
+0

Encuentro esta opción muy legible. El bit 'lambda ignored' me parece mágico: ¿podrías aclarar qué es exactamente lo que hace? – dangonfast

+4

Las rellamadas en un aplazado se llaman con un argumento. 'reactor.stop' no toma ningún argumento. 'lambda ignored: reactor.stop()' acepta y argumento, lo ignora y llama a 'reactor.stop' sin argumentos. –

+3

Sería un poco más convencional escribir: 'lambda _: reactor.stop' – DonGar

1

Quiero parar el reactor tan pronto como myFunction haya completado la tarea.

Entonces, crea una envoltura que hace el trabajo de myFunction y luego detiene el reactor?

def wrapper(reactor, *args): 
    myFunction(*args) 
    reactor.stop() 

reactor.callLater(0, wrapper, reactor, ...) 
0

Debe adjuntar la devolución de llamada al diferido que devuelve myFunction, ya que callLater no devuelve una función. Algo como esto podría funcionar:

reactor.callLater(0, lambda: myFunction(parameter1).addCallback(lambda _: reactor.stop()) 

Pero esto no ha sido probado.

Necesita escribir una nueva función (aquí el lambda _: reactor.stop()) porque las devoluciones de llamada a un diferido siempre toman el resultado hasta entonces.Si te encuentras querer utilizar devoluciones de llamada para sus efectos secundarios y que no se preocupan por la propagación de los valores de frecuencia, se podría definir un poco de función auxiliar:

def ignoringarg(f): 
    return lambda _: f() 

y luego hacer:

reactor.callLater(0, lambda: myFunction(paramater1).addCallback(ignoringarg(reactor.stop))) 

(Lo que sería realmente bueno sería definir un __rshift__ (y un análogo en el lugar) para la clase Deferred, por lo que podría hacer: myFunction(parameter1) >> reactor.stop, para cuando desee abandonar el argumento, o myFunction(parameter1) >>= someotherfunc para cuando desee propagar el argumento. Si crees que abusar de la sintaxis de haskell es "bueno", de todos modos.)

0

Si necesita disparar de respuesta con algún tipo de acción, sólo lo hacen (posiblemente no hay necesidad de volver diferido, o algo bajo). Solo para aclarar las cosas (utilizando puramente deferreds):

from twisted.internet import reactor, defer 

# That will be our deferred to play with 
# it has callback and errback methods 
d = defer.Deferred() 

def my_function(x): 
    print 'function', x 
    # need to trigger deferred upon function run? 
    # Lets tell it to do so: 
    d.callback(x) 

# That's our callback to run after triggering `d`  
def d_callback(y): 
    print 'callback ', y 

# now let's bind that callback to be actually launched by `d` 
d.addCallback(d_callback) 

# now adding another callback just to stop reactor 
# note lambda simply helps to agree number of arguments 
d.addCallback(lambda data: reactor.stop()) 

# so we'll call `my_function` in 2 secs, then it runs 
# then it triggers `d` to fire its callbacks 
# then `d` actually detonates the whole chain of its added callbacks 

reactor.callLater(2, my_function, 'asdf') # 'asdf' is some stupid param 

# Here how it works 
print 'Lets start!' 
reactor.run() 
print 'Done!'