Die Sache, die man über nicht blockierende Operationen (die man offensichtlich will) zu realisieren, ist, dass man mit ihnen keinen sequentiellen Code schreiben kann. Die Operationen blockieren nicht, weil sie nicht auf ein Ergebnis warten. Sie starten den Vorgang und geben die Steuerung an Ihre Funktion zurück. Also, getPage
gibt kein dateiähnliches Objekt zurück, von dem Sie lesen können, wie zum Beispiel urllib.urlopen
. Und selbst wenn, dann könnten Sie nicht lesen, bis die Daten verfügbar waren (oder es würde blockieren.) Und so können Sie nicht len()
darauf aufrufen, da das zuerst alle Daten lesen muss (was blockieren würde.)
Der Weg, mit nicht blockierenden Operationen in Twisted umzugehen ist durch Deferreds
, die Objekte für die Verwaltung von Rückrufen sind. getPage
gibt Deferred
zurück, was bedeutet, dass Sie dieses Ergebnis später erhalten werden. Sie können nichts mit dem Ergebnis tun, bis Sie es erhalten, so dass Sie Rückrufe an die Deferred
hinzufügen, und die Deferred
wird diese Rückrufe aufrufen, wenn das Ergebnis verfügbar ist. Das Rückruf kann dann tun, was Sie wollen:
def web_request(request)
def callback(data):
HttpResponse(len(data))
d = getPage("http://www.example.org")
d.addCallback(callback)
return d
Ein zusätzliches Problem bei Ihrem Beispiel ist, dass Ihre web_request
Funktion selbst blockiert. Was möchten Sie tun, während Sie darauf warten, dass das Ergebnis getPage
verfügbar wird? Tun Sie etwas anderes innerhalb web_request
, oder warten Sie einfach? Oder möchten Sie web_request
selbst nicht blockieren? Wenn ja, wie wollen Sie das Ergebnis produzieren? (Die offensichtliche Wahl in Twisted ist, eine andere Deferred
- oder sogar die gleiche wie getPage
zurückgibt, wie im obigen Beispiel. Dies ist jedoch nicht immer angemessen, wenn Sie Code in einem anderen Framework schreiben.)
Dort ist eine Möglichkeit, sequenziellen Code mit Deferreds
schreiben, obwohl es etwas restriktiv ist, schwieriger zu debuggen, und Kern Twisted Menschen weinen, wenn Sie es verwenden: twisted.internet.defer.inlineCallbacks
. Es verwendet die neue Generator-Funktion in Python 2.5, wo Sie Daten in einen Generator senden, und der Code aussehen würde etwas wie folgt aus:
@defer.inlineCallbacks
def web_request(request)
data = yield getPage("http://www.example.org")
HttpResponse(len(data))
Wie das Beispiel, das explizit die d
Latente zurückgegeben, dies würde nur funktionieren, wenn Der Aufrufer erwartet, dass web_request
nicht blockierend ist - der defer.inlineCallbacks
Dekorator verwandelt den Generator in eine Funktion, die Deferred
zurückgibt.
@Thomas: danke für die tolle Antwort !! : D Leider gibt das erste Beispiel verzögertes Objekt anstelle des HttpResponse-Objekts zurück !! – RadiantHex
Ihr Code hat das HttpResponse-Objekt auch nicht zurückgegeben, aber ja, es kommt darauf an, was ich über den Anrufer erklärt habe, der erwartet, dass web_request blockiert wird. Sie können nicht etwas von Blockieren in Nicht-Blockieren ändern, ohne zu ändern, wie es heißt. –
@Thomas so kann diese einfache Sache nicht getan werden? :( – RadiantHex