5

我想在 webapp 中使用Twisted 非阻塞 getPage方法,但与 urlopen 相比,使用这样的功能感觉相当复杂。

这是我试图实现的一个例子:

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

用getPage做类似的东西有那么难吗?

4

2 回答 2

20

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

Twisted 中处理非阻塞操作的方法是通过Deferreds,它们是用于管理回调的对象。getPage返回 a 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它使用 Python 2.5 中的新生成器功能,您可以将数据发送到生成器,代码看起来有点像这样:

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

与显式返回dDeferred 的示例一样,这仅在调用者期望web_request非阻塞时才有效——defer.inlineCallbacks装饰器将生成器转换为返回 a 的函数Deferred

于 2010-04-27T11:53:32.057 回答
4

我最近发布了对类似问题的回复,该回复提供了使用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(在本例中触发是一个事件)。

于 2010-04-27T16:47:39.507 回答