使用Twisted的getPage作为urlopen?

2024-05-23 22:46:58 发布

您现在位置:Python中文网/ 问答频道 /正文

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

这是我想要达到的一个例子:

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

与getPage有相似之处有那么难吗?


Tags: 方法函数webresponserequestdeftwistedurllib
2条回答

最近,我posted a responsesimilar question,它提供了使用getPage从URL获取内容所需的最少代码量。这里是为了完整起见:

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在本例中触发是一个事件)。

关于非阻塞操作(您似乎明确希望这样做)需要认识到的是,您不能真正用它们编写顺序代码。手术不会因为不等待结果而受阻。它们启动操作并将控制权返回到您的函数。因此,getPage不会像urllib.urlopen那样返回一个可以从中读取的类似文件的对象。即使是这样,在数据可用(或者阻塞)之前也无法从中读取数据,因此不能对其调用len(),因为这需要先读取所有数据(这将阻塞)

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.internet.defer.inlineCallbacks。它使用Python2.5中的新生成器特性,您可以将数据发送到生成器中,代码看起来有点像这样:

@defer.inlineCallbacks
def web_request(request)
    data = yield getPage("http://www.example.org")
    HttpResponse(len(data))

与显式返回dDeferred的示例一样,只有调用方希望web_request是非阻塞的,defer.inlineCallbacksdecorator将生成器转换为返回Deferred的函数时,此方法才有效。

相关问题 更多 >