2013-06-25 62 views
1

我有一个API管理器,连接到一个URL并抓取一些json。很简单。从方法 剪切:urlopen随机冻结,timout被忽略

req = Request(url) 
socket.setdefaulttimeout(timeout) 
resp = urlopen(req, None, timeout) 
data = resp.read() 
resp.close() 

它正常工作的大部分时间,但在随机时间间隔需要5秒完成请求。即使超时设置为0.5或1.0或其他。 我已经记录得非常紧密,所以我100%确定需要时间的行是#3号(即resp = urlopen(req,None,timeout))。

我用尽所有的解决方案在伊夫超时装饰和定时器等的话题发现 (要列出其中一些: Python urllib2.urlopen freezes script infinitely even though timeout is setHow can I force urllib2 to time out?Timing out urllib2 urlopen operation in Python 2.4Timeout function if it takes too long to finish

但没有任何工程。我的印象是,线程冻结,而urlopen做一些事情,当它完成时解冻,然后所有的定时器和超时返回超时错误。但执行时间仍然超过5秒。

我发现了this关于urllib2和处理分块编码的旧邮件列表。所以如果问题仍然存在,那么解决方案可能是编写一个基于httplib.HTTP而不是httplib.HTTPConnection的自定义urlopen。 另一个可能的解决方案是尝试一些多线程的魔法....

这两种解决方案似乎aggresive。它让我感到困惑,超时不能一直工作。

脚本的执行时间不超过0.5s是非常重要的。任何知道我为什么遇到冻结或者可能帮助我的方法的人?

根据接受的答案更新: 我改变了方法并使用curl代替。一起w unix超时它就像我想要的那样工作。示例代码如下:

t_timeout = str(API_TIMEOUT_TIME) 
c_timeout = str(CURL_TIMEOUT_TIME) 
cmd = ['timeout', t_timeout, 'curl', '--max-time', c_timeout, url] 
prc = Popen(cmd, stdout=PIPE, stderr=PIPE) 
response = prc.communicate() 

由于curl只接受int作为超时我添加了超时。超时接受浮动。

回答

1

纵观源代码,timeout的值实际上是Python在从远程主机接收数据包之间等待的最长时间。

因此,如果将超时设置为两秒,并且远程主机以每秒一个数据包的速率发送60个数据包,则超时将永远不会发生,尽管整个过程仍需要60秒。

由于urlopen()函数在远程主机完成发送所有HTTP标头之前不会返回,因此如果它非常缓慢地发送标头,那么您可以做的事情就不多了。

如果您需要一个整体时间限制,您可能必须实现您自己的具有非阻塞I/O的HTTP客户端。

+0

完美答案。谢谢。即使我觉得应该有一个可用的总体超时。如果我按照建议实现了一个自定义的HTTP客户端,我会更新病毒 – user2520443