Pregunta

Estoy tratando de averiguar cómo puedo hacer que mi código asíncrono utilizando más retorcida.

  • devuelve una función de un objeto diferido
  • Luego añadir una lista de devoluciones de llamada
  • la primera devolución de llamada se llama después de la función diferida proporciona algún resultado a través de deferred_obj.callback
  • a continuación, en la cadena de devoluciones de llamada, la primera llamada de retorno va a hacer algo con los datos y llamar a la segunda llamada de retorno
  • y etc.

Sin embargo devoluciones de llamada encadenados no será considerado asíncrono porque están encadenados y el bucle de eventos mantendrá disparando cada uno de ellos al mismo tiempo hasta que no hay más, ¿verdad?

Sin embargo, si tengo un objeto diferido, y adjunto como su devolución de llamada la deferred_obj.callback como en d.addCallback(deferred_obj.callback) entonces esto va a ser considerado asíncrono, porque el deferred_obj está esperando los datos y, a continuación el método que pasar los datos está a la espera de los datos, así, sin embargo una vez que d.callback 'd' objeto procesa los datos entonces se llama deferred_obj.callback sin embargo puesto que este objeto se difiere, a diferencia del caso de las devoluciones de llamada encadenados, se ejecutará de forma asíncrona ... correcto?

Suponiendo que todo de mi código es no bloqueante, esto significa que encadenan las devoluciones de llamada no son asíncronas, mientras deferreds encadenados son, ¿verdad?

¿Fue útil?

Solución

Las devoluciones de llamada son (por defecto) síncrono. Sin embargo, como señala el doc Twisted a cabo:

Si necesita uno diferido que esperar en otro, todo lo que necesita hacer es devolver un diferido de un método añadido a addCallbacks.

Así que usted puede utilizar eso para hacer algo de procesamiento asíncrono en su cadena de devolución de llamada. Vamos a hacer lo siguiente:

from twisted.internet import reactor, defer

def callback_func_2(result, previous_data):
    # here we pass the result of the deferred down the callback chain
    # (done synchronously)
    print "calling function 1 on result:%s with previous result:%s" % (result, previous_data)
    return result

def callback_func(result):
    #let's do some asynchronous stuff in this callback
    # simple trick here is to return a deferred from a callback 
    # instead of the result itself.
    # 
    # so we can do asynchronous stuff here, 
    # like firing something 1 second later and have 
    # another method processing the result
    print "calling function 1 on result:%s" % result
    d = defer.Deferred()
    reactor.callLater(1, d.callback, "second callback")
    d.addCallback(callback_func_2, result)
    return d

def do():
    d = defer.Deferred()
    reactor.callLater(1, d.callback, "first callback")
    d.addCallback(callback_func)
    return d

do()
reactor.run()

Otros consejos

Ordenar de, pero no hay concurrencia en este tipo de procesamiento de eventos. No hay nueva función se le llama hasta que el código se pone de nuevo al bucle de eventos. Por lo que la cadena de devoluciones de llamada es sincrónico. Es sólo asíncrono en el bucle de eventos.

Esta es una advertencia de este tipo de programación, los controladores ejecutan más rápidamente y volver al bucle caso lo antes posible. No debe hacer cualquier tarea que consume tiempo en un controlador.

El uso de un diferido no hacer que su código asíncrono.

import time
from twisted.internet import defer
from twisted.internet import reactor

def blocking(duration, deferred):
    print "start blocking"
    time.sleep(duration)
    print "finished blocking"
    deferred.callback(True)

def other_task():
    print "working..."
    reactor.callLater(1, other_task)

def finish(result):
    print "stopping reactor in 2sec"
    reactor.callLater(2, reactor.stop)

def failed(reason):
    print reason
    print "stopping reactor in 2sec"
    reactor.callLater(2, reactor.stop)

def main():
    d = defer.Deferred()
    d.addCallbacks(finish, failed)
    reactor.callLater(0, blocking, 5, d)

if __name__ == "__main__":
    reactor.callLater(0, other_task)
    main()
    reactor.run()

Si ha de larga duración código sincrónico, puede deferToThread o dividirla en iteraciones cortas usando un cooperador (twisted.internet.task)

Si desea hacer que su código sea más asíncrona con un enfoque limpio, entonces echa un vistazo a este marco:

https://github.com/iogf/untwisted

Tiene código ordenado, con una documentación clara. El enfoque para tratar con los modelos asíncronos es sencillo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top