defer.execute ausführt tatsächlich die Funktion in einer blockierenden Art und Weise, in dem gleichen Thread und Sie sind richtig, dass defer.execute(f, args, kwargs)
macht die gleichen wie defer.succeed(f(*args, **kwargs))
außer dass defer.execute
einen Rückruf zurück, der die errback hatte gefeuert, wenn die Funktion f löst eine Ausnahme aus. Wenn in Ihrem Beispiel defer.succeed die Funktion eine Ausnahme ausgelöst hat, würde sie sich nach außen ausbreiten, was nicht erwünscht sein könnte.
Zum leichteren Verständnis, ich werde nur die Quelle defer.execute hier einfügen:
def execute(callable, *args, **kw):
"""Create a deferred from a callable and arguments.
Call the given function with the given arguments. Return a deferred which
has been fired with its callback as the result of that invocation or its
errback with a Failure for the exception thrown.
"""
try:
result = callable(*args, **kw)
except:
return fail()
else:
return succeed(result)
Mit anderen Worten, ist defer.execute
nur eine Verknüpfung einer Sperrfunktion des Ergebnis zu nehmen, wie eine Dose, die Sie verschoben Fügen Sie dann Callbacks/Errbacks hinzu. Die Callbacks werden mit normaler Verkettungssemantik abgefeuert. Es scheint ein bisschen verrückt, aber Verzögerter kann "feuern" bevor Sie Callbacks hinzufügen und die Callbacks werden immer noch aufgerufen.
So Ihre Frage zu beantworten, warum ist das nützlich? Nun, defer.execute
ist sowohl zum Testen/Mocking als auch zum einfachen Integrieren einer asynchronen API mit synchronem Code nützlich.
Auch nützlich ist defer.maybeDeferred
, die die Funktion aufruft und dann, wenn die Funktion bereits zurückgibt, verzögert einfach zurück, sonst funktioniert ähnlich wie defer.execute
. Dies ist nützlich, wenn Sie eine API schreiben, die eine aufrufbare Funktion erwartet, die Ihnen beim Aufrufen eine Verzögerung gibt und Sie auch normale Blockierungsfunktionen akzeptieren möchten.
Zum Beispiel, sagen Sie, Sie hatten eine Anwendung, die Seiten abgerufen und Dinge damit gemacht hat. Und aus irgendeinem Grund mussten Sie dies synchron für einen bestimmten Anwendungsfall ausführen, z. B. in einem Single-Shot-Crontab-Skript oder als Reaktion auf eine Anfrage in einer WSGI-Anwendung, aber immer noch die gleiche Codebasis. Wenn Ihr Code so aussah, könnte es geschehen:
from twisted.internet import defer
from twisted.web.client import getPage
def process_feed(url, getter=getPage):
d = defer.maybeDeferred(getter, url)
d.addCallback(_process_feed)
def _process_feed(result):
pass # do something with result here
dies in einem synchronen Kontext ausführen zu können, ohne den Reaktor, könnte man einfach eine alternative Getter-Funktion übergeben, etwa so:
from urllib2 import urlopen
def synchronous_getter(url):
resp = urlopen(url)
result = resp.read()
resp.close()
return result
+ 1 zur Erläuterung defer.maebeDeferred –