urlopen随机冻结,忽略超时

时间:2013-06-25 14:37:03

标签: python timeout urllib2

我有一个连接到URL的API管理器并抓取一些json。非常简单。 从方法切入:

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做了一些事情,当它完成时解冻,然后所有的定时器和超时返回w超时错误。但执行时间仍然超过5秒。

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

这两种解决方案似乎都具有攻击性。它让我觉得超时不会一直有效。

脚本的执行时间不超过0.5秒非常重要。有谁知道为什么我会遇到冻结或者可能有办法帮助我?

根据已接受的答案进行更新: 我改变了方法并使用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 个答案:

答案 0 :(得分:1)

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

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

由于urlopen()函数在远程主机完成所有HTTP标头的发送后才会返回,如果它发送的标题非常慢,那么你就无法做到这一点。

如果您需要总时间限制,则可能必须使用非阻塞I / O实现自己的HTTP客户端。