我正在使用tornado.httpclient.AsyncHTTPClient.fetch
从列表中获取域。当我以较大的间隔(例如500)将域放入fetch时,一切都很好,但是当我将interval减少到100时,下一个异常会不时发生:
Traceback (most recent call last):
File "/home/crchemist/python-2.7.2/lib/python2.7/site-packages/tornado/simple_httpclient.py", line 289, in cleanup
yield
File "/home/crchemist/python-2.7.2/lib/python2.7/site-packages/tornado/stack_context.py", line 183, in wrapped
callback(*args, **kwargs)
File "/home/crchemist/python-2.7.2/lib/python2.7/site-packages/tornado/simple_httpclient.py", line 384, in _on_chunk_length
self._on_chunk_data)
File "/home/crchemist/python-2.7.2/lib/python2.7/site-packages/tornado/iostream.py", line 180, in read_bytes
self._check_closed()
File "/home/crchemist/python-2.7.2/lib/python2.7/site-packages/tornado/iostream.py", line 504, in _check_closed
raise IOError("Stream is closed")
IOError: Stream is closed
这种行为的原因是什么?代码如下:
^{pr2}$
看起来你在写类似网络爬虫的东西。你的问题是直接由超时引起的,但在深层次上,与龙卷风中的平行模式有关。在
当然,tornado中的
AsyncHTTPClient
可以自动对请求进行排队。实际上,AsyncHTTPClient
将成批发送10个请求(默认情况下),并阻塞以等待其结果,然后发送下一批。批内请求是非块并行处理,但批间请求是块请求。每个请求的回调不是在请求完成后立即调用的,而是在一批请求完成之后,然后调用10个回调。在回到您的问题,您不需要使用
ioloop.PeriodicCallback
来递增地发出请求,因为tornado中的AsyncHTTPClient
可以自动对请求进行排队。您可以一次性分配所有请求,让AsyncHTTPClient
来安排请求。在但问题是等待队列中的请求仍然占用超时时间!因为请求在批处理之间被阻塞。稍后的请求在这里简单地阻塞,然后一批一批地发送,而不是将它们放入一个特殊的就绪队列中,在响应到达后发送一个新的请求。在
因此,如果安排了许多请求,则设置为20秒的默认超时太短。如果您只是做一个演示,可以直接将超时设置为
float('inf')
。如果做了一些严重的事情,你必须使用try/except重试循环。在您可以在这里找到如何从^{} 设置超时。在
最后,我编写了一个简单的程序,使用
AsyncHTTPClient
从ZJU在线判决系统中获取数千页。你可以试试这个,然后重写到你的爬虫。在我的网络上,它可以在2分钟内获取2800页。非常好的结果,比串行获取快10倍(完全匹配并行大小)。在额外:
如果您有大量的页面需要获取,并且您是那种追求最佳性能的人,那么您可以查看一下
Twisted
。我用Twisted
编写了一个相同的程序,并将其粘贴到我的Gist上。它的结果是非常棒的:在40秒内就可以获取2800页。在注意,} 对象配置了一个
tornado.ioloop.PeriodicCallback
takes a cycle time in integer ms,而^{connect_timeout
和/或一个request_timeout
的float秒(see doc)。在“浏览互联网的用户觉得,当从单击到响应的延迟小于100毫秒时,响应是“即时的”(from wikipedia)请参见this ServerFault question for normal latency values。在
IOError: Stream is closed
被有效地引发以通知您连接超时而没有完成,或者更准确地说,您在尚未打开的管道上手动调用了回调。这很好,因为延迟大于100ms是正常的;如果您希望您的回迁能够可靠地完成,那么应该提高这个值。在一旦将超时设置为合理的值,请考虑将获取打包到try/except retry循环中,因为这是一个正常的异常,您可以预期在生产中发生。小心设置重试限制!在
既然您使用的是异步框架,为什么不让它自己处理异步回调,而不是在固定的时间间隔内运行所述回调呢?Epoll/kqueue are efficient and supported by this framework.
^逐字复制from the doc。在
如果你走这条路,唯一的问题就是对你的请求队列进行编码,这样你就有了最大限度的开放连接。否则,当你做严重的刮擦时,你很可能会出现竞速状态。在
自从我自己接触龙卷风已经有大约1年了,所以请告诉我这个回答是否有不准确之处,我会修改的。在
相关问题 更多 >
编程相关推荐