之前写了一个多线程爬取壁纸程序后,发现有时候运行起来,会有线程在打开某张图片的链接时卡住(似乎一般是在图片比较大的时候),报错也不报,许久都不能恢复。。

可以设置timeout参数来防止requests时间过长,并捕捉错误信息然后让再让其requests多几次:

  1. try:
  2. downloadPic(urlNum, self.threadID)
  3. except Exception as e:
  4. print('Thread %d:\tTry to request again #1' %(self.threadID))
  5. # 请求超时,再试几次
  6. requestOK = False # 标记
  7. exceptionMs = str(e) # 先保存错误信息
  8. for i in range(2):
  9. try:
  10. downloadPic(urlNum, self.threadID)
  11. requestOK = True
  12. break
  13. except Exception as e:
  14. print('Thread %d:\tTry to request again #%d' %(self.threadID, (i+2)))
  15. # 请求三次还是不成功
  16. if not requestOK:
  17. downloadFail.append(picNames[urlNum]) # 记录下载失败的图片
  18. print('Thread %d:\t%s' %(self.threadID, exceptionMs)) # 输出错误信息

但事实上,即使设置了timeout,线程仍有卡死的可能。

网上的一种做法是使用socket.setdefaulttimeout(seconds)来解决,但亲测并无卵用。

深究timeout的失效原因,发现是因为requests请求上设置的timeout判断的并不是整个请求的总时间,而是从与服务器连接成功后,客户端开始接受服务器的数据为计算起点的。

也就是说,若是requests请求停在了与服务器成功连接之前的步骤,那此时无论停了多久,都不会开始计算停留时间,所以永远都触发不到timeout。

那么与服务器连接前究竟是卡在了哪里呢?据网上说是卡在了DNS解析。

于是,我把DNS更改为阿里公共DNS(223.5.5.5 / 223.6.6.6)。

之后到目前是没再出现requests卡死的情况了!

所以总结一下:

一定要设置timeout,并使用可靠的DNS服务器地址。

发表评论

邮箱地址不会被公开。 必填项已用*标注