python - urlopen 随机卡住,超时被忽略

标签 python timeout urllib2

我有一个 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 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 执行某些操作时,线程会卡住,完成后它会解冻,然后所有计时器和超时都会返回超时错误。但执行时间仍然超过5s。

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

这两种解决方案似乎都具有攻击性。令我烦恼的是,超时并不能完全发挥作用。

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

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

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作为超时,所以我添加了超时。超时接受 float 。

最佳答案

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

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

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

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

关于python - urlopen 随机卡住,超时被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17300268/

相关文章:

python - 使用身份验证从 https 下载文件

java - python AES加密java解密

ruby-on-rails - Rescue_from 不会从 View 或助手中拯救 Timeout::Error

ssl - 使用 urllib2 连接 sslv3 页面

winapi - C++ Pipe ReadFile 函数在 Windows XP 中设置超时

php - file_get_contents 给出无法打开流 : Connection timed out error for file on same server

python - 使用没有 Selenium 的 Python 下载文件,例如 Chrome 的 "Save Link As"

python - 从 PHP 脚本在 Python 中调用 Webdriver 时,Firefox 无法打开

python - "if"和 "if not"之间的性能或风格差异?

python - 根据pandas中的多个条件添加新的数据框