我想在webapp中使用 Twisted non-blocking getPage 方法,但与urlopen相比,使用此类函数感觉相当复杂。
这是我想要实现的一个例子:
def web_request(request):
response = urllib.urlopen('http://www.example.org')
return HttpResponse(len(response.read()))
与getPage有类似之处是否很难?
答案 0 :(得分:20)
要实现非阻塞操作(您似乎明确需要)的事情是您无法用它们真正编写顺序代码。操作不会阻止,因为它们不会等待结果。他们启动操作并将控制权返回给您的功能。因此,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人在使用它时会哭: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 pattern(getPage
在此实例中触发为事件)。