使用Twisted的getPage作为urlopen?

时间:2010-04-27 10:48:21

标签: python django twisted urllib2 urllib

我想在webapp中使用 Twisted non-blocking getPage 方法,但与urlopen相比,使用此类函数感觉相当复杂。

这是我想要实现的一个例子:

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

与getPage有类似之处是否很难?

2 个答案:

答案 0 :(得分:20)

要实现非阻塞操作(您似乎明确需要)的事情是您无法用它们真正编写顺序代码。操作不会阻止,因为它们不会等待结果。他们启动操作并将控制权返回给您的功能。因此,getPage不会返回类似文件的对象,您可以像urllib.urlopen那样返回。即使它确实如此,在数据可用之前你也无法从中读取(或者它会阻塞。)所以你不能在它上面调用len(),因为它需要先读取所有数据(哪会阻止。)

在Twisted中处理非阻塞操作的方法是通过Deferreds,它们是用于管理回调的对象。 getPage会返回Deferred,表示“稍后会收到此结果”。在获得结果之前,您无法对结果执行任何操作,因此您将回调添加到DeferredDeferred会在结果时调用这些回调是可用。然后,该回调可以按照您的要求执行:

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 Deferred的示例类似,只有在调用者希望web_request为非阻塞时才会有效 - defer.inlineCallbacks装饰器将生成器转换为返回Deferred

的函数

答案 1 :(得分:4)

posted a response最近similar question提供了使用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用于处理事件的reactor patterngetPage在此实例中触发为事件)。