Использовать Twisted getPage в качестве урлопена? - PullRequest
5 голосов
/ 27 апреля 2010

Я хотел бы использовать Скрученный неблокирующий метод getPage в веб-приложении, но использовать такую ​​функцию довольно сложно по сравнению с urlopen.

Это пример того, чего я пытаюсь достичь:

def web_request(request):
   response = urllib.urlopen('http://www.example.org')
   return HttpResponse(len(response.read()))

Так сложно иметь что-то похожее с getPage?

Ответы [ 2 ]

20 голосов
/ 27 апреля 2010

При работе с неблокирующими операциями (что, как вам кажется, явно требуется) нужно понимать, что вы не можете написать последовательный код с ними.Операции не блокируются, потому что они не ждут результата.Они запускают операцию и возвращают управление вашей функции.Таким образом, 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.

4 голосов
/ 27 апреля 2010

I недавно опубликовал ответ на аналогичный вопрос , в котором содержится минимальный объем кода, необходимый для получения содержимого из URL-адреса с использованием getPage. Вот для полноты картины:

from twisted.web.client import getPage
from twisted.internet import reactor

url = 'http://aol.com'

def print_and_stop(output):
    print output
    if reactor.running:
       reactor.stop()

if __name__ == '__main__':
    print 'fetching', url
    d = getPage(url)
    d.addCallback(print_and_stop)
    reactor.run()

Имейте в виду, что вам, вероятно, понадобится более глубокое понимание схемы реактора , используемой Twisted для обработки событий (getPage в данном случае - запуск).

...