我想在 webapp 中使用Twisted 非阻塞 getPage方法,但与 urlopen 相比,使用这样的功能感觉相当复杂。
这是我试图实现的一个例子:
def web_request(request):
response = urllib.urlopen('http://www.example.org')
return HttpResponse(len(response.read()))
用getPage做类似的东西有那么难吗?
关于非阻塞操作(您似乎明确想要)要实现的事情是您不能真正用它们编写顺序代码。这些操作不会阻塞,因为它们不等待结果。他们启动操作并将控制权返回给您的函数。因此,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))
与显式返回d
Deferred 的示例一样,这仅在调用者期望web_request
非阻塞时才有效——defer.inlineCallbacks
装饰器将生成器转换为返回 a 的函数Deferred
。
我最近发布了对类似问题的回复,该回复提供了使用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
(在本例中触发是一个事件)。