При работе с неблокирующими операциями (что, как вам кажется, явно требуется) нужно понимать, что вы не можете написать последовательный код с ними.Операции не блокируются, потому что они не ждут результата.Они запускают операцию и возвращают управление вашей функции.Таким образом, getPage
не возвращает файловый объект, из которого вы можете прочитать, как urllib.urlopen
.И даже если это произойдет, вы не сможете читать с него, пока данные не будут доступны (или они заблокируются). И поэтому вы не можете вызвать len()
для него, так как для этого нужно сначала прочитать все данные (что будетblock.)
Способ работы с неблокирующими операциями в Twisted - через Deferreds
, которые являются объектами для управления обратными вызовами.getPage
возвращает Deferred
, что означает "вы получите этот результат позже".Вы ничего не можете сделать с результатом, пока не получите его, поэтому вы добавляете обратных вызовов к Deferred
, и Deferred
будет вызывать эти обратные вызовы, когда результат станет доступным ,Затем этот обратный вызов может делать то, что вы хотите:
def web_request(request)
def callback(data):
HttpResponse(len(data))
d = getPage("http://www.example.org")
d.addCallback(callback)
return d
Дополнительная проблема с вашим примером состоит в том, что ваша функция web_request
сама блокирует.Что вы хотите сделать, пока ждете, пока результат getPage
станет доступным?Сделайте что-нибудь еще в web_request
или просто подождите?Или хочешь превратить web_request
сам неблокирующий?Если да, то как вы хотите получить результат?(Очевидный выбор в Twisted - это вернуть еще один Deferred
- или даже тот же, что и getPage
, как в примере выше. Однако это может не всегда подходить, если вы пишете код в другой среде.)
Там - это способ написания последовательного кода с использованием Deferreds
, хотя это несколько ограничительно, сложнее в отладке, и основные пользователи Twisted плачут, когда вы его используете: twisted.internet.defer.inlineCallbacks
.Он использует новую функцию генератора в Python 2.5, где вы можете отправлять данные в генератор, и код будет выглядеть примерно так:
@defer.inlineCallbacks
def web_request(request)
data = yield getPage("http://www.example.org")
HttpResponse(len(data))
Как в примере, который явно возвращает d
Отложено, это 'будет работать только в том случае, если вызывающая сторона ожидает, что web_request
неблокирует - декоратор defer.inlineCallbacks
превращает генератор в функцию, которая возвращает Deferred
.