Verdreht: Unterschied zwischen `defer.execute` und` threads.deferToThread`

Was ist der Unterschied zwischen defer.execute() und threads.deferToThread() in twisted? Beide nehmen die gleichen Argumente – eine Funktion und Parameter, um sie mit zu nennen – und eine Verzögerung zurückzugeben, die mit dem Ergebnis des Aufrufs der Funktion abgefeuert wird.

Die threads Version erklärt explizit, dass es in einem Thread ausgeführt wird. Allerdings, wenn die defer Version nicht, dann was würde jemals der Punkt sein, es zu nennen? Code, der im Reaktor läuft, sollte niemals blockieren, also muss jede Funktion, die es anruft, nicht blockieren. An diesem Punkt könntest du einfach nur defer.succeed(f(*args, **kwargs)) anstatt defer.execute(f, args, kwargs) mit den gleichen Ergebnissen.

One Solution collect form web for “Verdreht: Unterschied zwischen `defer.execute` und` threads.deferToThread`”

Defer.execute führt die Funktion zwar in einer blockierenden Weise aus, in demselben Thread und du bist richtig in diesem defer.execute(f, args, kwargs) tut das selbe wie defer.succeed(f(*args, **kwargs)) Außer dass defer.execute einen Rückruf zurücksendet, bei dem der Fehler gefeuert wurde, wenn die Funktion f eine Ausnahme auslöst. Mittlerweile, wenn die Funktion eine Ausnahme auslöste, würde sie sich nach außen ausbreiten, was nicht erwünscht ist.

Um das Verständnis zu erleichtern, füge ich einfach die Quelle von defer.execute hier:

 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, defer.execute ist nur eine Verknüpfung, um das Ergebnis einer Sperrfunktion als deferred zu nehmen, mit dem Sie dann Callbacks / Errorbacks hinzufügen können. Die Rückrufe werden mit normaler Verkettungssemantik abgefeuert. Es scheint ein bisschen verrückt, aber Deferreds können 'Feuer', bevor Sie Callbacks hinzufügen und die Callbacks werden immer noch aufgerufen.


Also, um Ihre Frage zu beantworten, warum ist das nützlich ? Nun, defer.execute ist sowohl für das Testen / Mocking als auch die einfache Integration eines asynchronen AIP mit synchronem Code nützlich.

Auch nützlich ist defer.maybeDeferred die die Funktion aufruft und dann, wenn die Funktion bereits ein deferred zurückgibt, gibt es einfach zurück, sonst funktioniert ähnlich wie defer.execute . Dies ist nützlich für, wenn Sie eine API schreiben, die eine aufrufbare, wenn aufgerufen gibt Ihnen eine verzögerte, und Sie wollen in der Lage, normale Blocking-Funktionen als auch akzeptieren.

Zum Beispiel, sagen Sie, Sie hatten eine Anwendung, die Seiten geholt und tat es mit ihm. Und aus irgendeinem Grund musstest du das in einer synchronen Weise für einen bestimmten Anwendungsfall laufen lassen, wie in einem Single-Shot-Crontab-Skript oder als Antwort auf eine Anfrage in einer WSGI-Anwendung, aber immer noch die gleiche Codebasis behalten. Wenn dein Code so aussah, konnte man das machen:

 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 

Um dies in einem synchronen Kontext zu führen, ohne den Reaktor, könnte man einfach eine alternative Getterfunktion passieren, so wie:

 from urllib2 import urlopen def synchronous_getter(url): resp = urlopen(url) result = resp.read() resp.close() return result 
Python ist die beste Programmiersprache der Welt.