Frage

Ich versuche herauszufinden, wie ich meinen Code mit Twisted asynchroner machen kann.

  • Eine Funktion gibt ein aufgeschobenes Objekt zurück
  • Dann füge ich eine Liste von Rückrufen hinzu
  • Der erste Rückruf wird aufgerufen, nachdem die aufgeschobene Funktion ein gewisses Ergebnis durch liefert deferred_obj.callback
  • In der Kette der Rückrufe wird der erste Rückruf mit den Daten etwas unternehmen und den zweiten Rückruf rufen
  • und ETC.

Allerdings werden verkettete Rückrufe nicht als asynchron angesehen, da sie gekettet sind und die Ereignisschleife jeden von ihnen gleichzeitig abfeuern wird, bis es nicht mehr gibt, oder?

Wenn ich jedoch ein verzögertes Objekt habe und als Rückruf die deferred_obj.callback wie in angehängt habe d.addCallback(deferred_obj.callback) Dann wird dies als asynchron angesehen, da der Deferred_OBJ auf die Daten wartet und dann auch die Methode, die die Daten übergibt, auch auf Daten wartet. Sobald ich jedoch die Daten verarbeitet, ruft sie desfered_obj auf. Rückruf jedoch, da dieses Objekt jedoch aufgeschoben wird, im Gegensatz zum Fall von geketteten Rückernständen wird es asynchron ausführen ... richtig?

Angenommen, der gesamte Code ist nicht blockiert, bedeutet dies, dass gekettete Rückrufe nicht asynchron sind, während gekettete Aufschaltungen richtig sind?

War es hilfreich?

Lösung

Die Rückrufe sind (standardmäßig) synchron. Allerdings als die Twisted Doc weist darauf hin:

Wenn Sie einen aufgeschobenen auf einen anderen warten müssen, müssen Sie lediglich eine von einer Methode hinzugefügten Methode zurückgeben, die addCallbacks hinzugefügt wurde.

Sie können damit eine asynchrone Verarbeitung in Ihrer Rückrufkette durchführen. Lass uns das tun:

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()

Andere Tipps

Art, aber es gibt keine Gleichzeitigkeit in dieser Art der Ereignisverarbeitung. Es wird kein neuer Rückruf angerufen, bis der Code zur Ereignisschleife zurückgeht. Die Rückrufkette ist also synchron. Es ist nur asynchron in der Veranstaltungsschleife.

Dies ist eine Einschränkung dieser Art von Programmierung, die Handler werden am schnellsten ausgeführt und kehren so schnell wie möglich zur Ereignisschleife zurück. Es sollte keine zeitaufwändige Aufgabe in einem Handler erledigen.

Durch die Verwendung eines aufgeschobenen Codes ist Ihr Code nicht asynchron.

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()

Wenn Sie über langjährigen Synchroncode verfügen, können Sie ihn mit einem Cooperator (Twisted.Internet.Task) in kurze Iterationen einteilen oder in kurze Iterationen zerlegen).

Wenn Sie Ihren Code mit einem sauberen Ansatz asynchroner machen möchten, lesen Sie dieses Framework:

https://github.com/iogf/untwisted

Es hat einen ordentlichen Code mit klarer Dokumentation. Der Ansatz für den Umgang mit asynchronen Modellen ist unkompliziert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top