我有一个连接到URL并获取一些json的API管理器。很简单的。
切法:
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 set,
How can I force urllib2 to time out?,Timing out urllib2 urlopen operation in Python 2.4,Timeout function if it takes too long to finish
)
但是没有任何效果。我的印象是,在urlopen执行某项操作时,线程冻结,当它完成时,它冻结,然后所有计时器和超时返回w超时错误。但是执行时间仍超过5s。
我发现有关urllib2和分块编码处理的this旧邮件列表。因此,如果问题仍然存在,那么解决方案可能是基于httplib.HTTP而不是httplib.HTTPConnection编写自定义urlopen。
另一个可能的解决方案是尝试一些多线程魔术。
两种解决方案似乎都是激进的。令我感到困惑的是,超时并不能一直起作用。
脚本的执行时间不超过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作为超时,所以我添加了超时。超时接受浮点数。
最佳答案
查看源代码,实际上timeout
值是Python在两次从远程主机接收数据包之间等待的最长时间。
因此,如果将超时设置为2秒,并且远程主机以每秒1个数据包的速率发送60个数据包,则超时将永远不会发生,尽管整个过程仍将花费60秒。
由于urlopen()
函数直到远程主机完成所有HTTP标头的发送才返回,因此,如果它发送标头的速度很慢,那么您将无能为力。
如果需要总体时间限制,则可能必须使用无阻塞I / O来实现自己的HTTP客户端。
关于python - urlopen随机卡住,超时被忽略,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17300268/