urlopen随机冻结,timout被忽略



我有一个API管理器,它连接到一个URL并获取一些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 urlib2.urllopen即使设置了超时也会无限冻结脚本,如何强制urllib2超时?,Python 2.4中的urllib2 urlopen操作超时,如果完成时间过长则超时函数)

但什么都不管用。我的印象是,当urlopen做某事时,线程会冻结,当它完成时,它会解冻,然后所有计时器和超时都会返回w个超时错误。但是执行时间仍然大于5s。

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

这两种解决方案似乎都具有攻击性。超时并不能一直起作用,这让我很恼火。

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

根据接受的答案更新:我改变了方法,改为使用旋度。加上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作为timeout,所以我添加了timeout。timeout接受浮点值。

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

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

由于urlopen()函数在远程主机发送完所有HTTP标头后才会返回,因此如果它发送标头的速度非常慢,则对此无能为力

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

最新更新