我应该在 urllib.urlopen() 之后调用 close() 吗?
Posted
技术标签:
【中文标题】我应该在 urllib.urlopen() 之后调用 close() 吗?【英文标题】:should I call close() after urllib.urlopen()? 【发布时间】:2010-12-04 02:30:51 【问题描述】:我是 Python 新手,正在阅读别人的代码:
urllib.urlopen()
后面应该跟urllib.close()
吗?否则,会泄漏连接,对吗?
【问题讨论】:
【参考方案1】:urllib.request 模块使用 HTTP/1.1 并在其 HTTP 请求中包含
Connection:close
标头。
来自官方文档,您可以查看here。
【讨论】:
【参考方案2】:您基本上确实需要在使用 IronPython 时显式关闭您的连接。超出范围的自动关闭依赖于垃圾收集。我遇到了这样一种情况,即垃圾收集没有运行很长时间,以至于 Windows 用完了套接字。我以高频率轮询网络服务器(即与 IronPython 一样高,并且连接允许,~7Hz)。我可以看到 PerfMon 上的“已建立连接”(即正在使用的套接字)不断上升。解决方案是在每次调用urlopen
后调用gc.collect()
。
【讨论】:
【参考方案3】:就像@Peter 所说,超出范围打开的 URL 将有资格进行垃圾收集。
不过,还要注意urllib.py
定义:
def __del__(self):
self.close()
这意味着当该实例的引用计数为零时,它的__del__
方法将被调用,因此它的close
方法也将被调用。引用计数达到零的最“正常”方式是简单地让实例超出范围,但没有什么严格阻止您尽早使用显式 del x
(但是它不直接调用 __del__
而只是将引用计数减一)。
明确关闭你的资源肯定是一种很好的方式——尤其是当你的应用程序冒着使用过多上述资源的风险时——但是如果你不这样做,Python 会自动为你清理做一些有趣的事情,比如维护(循环?)对不再需要的实例的引用。
【讨论】:
然而,有可能超出垃圾收集器——我有过创建文件句柄比关闭它们更快的情况[但是显式的gc.collect()
调用或 @ 987654329@,收拾东西]。【参考方案4】:
close
方法必须在 urllib.urlopen
的 result 上调用,而不是在 urllib
模块本身上调用,正如您正在考虑的那样(当您提及urllib.close
——不存在)。
最好的方法:代替x = urllib.urlopen(u)
等,使用:
import contextlib
with contextlib.closing(urllib.urlopen(u)) as x:
...use x at will here...
with
语句和 closing
上下文管理器将确保即使存在异常也能正确关闭。
【讨论】:
像data = urllib2.urlopen('url').read()
这样的事情怎么样
在 Python 3 中,添加了对 with 语句的直接支持。使用 urllib.urlopen(u) 作为 x: ...
为什么python3 doc 在这个(咳咳)上下文中仍然提到contextlib.closing
?
@ÉricAraujo:在 python 3 中,urllib.urlopen
根本不存在。
它被移动到一个新的子模块 urllib.request:docs.python.org/3/library/…【参考方案5】:
严格来说,这是真的。但实际上,一旦(如果)urllib
超出范围,自动垃圾收集器将关闭连接。
【讨论】:
这在 Python 的一些实现中是正确的,但是 Python 语言并不能保证一旦对象超出范围就会关闭。参看。 jython @gnibbler 这个答案的作者没有说它会发生只要它就会发生。 @Piotr,但如果我有一个循环打开 url 并且 GC 没有足够快地获取它们,程序可能会崩溃。这是一种非常草率的做事方式,不属于生产代码。 no-op GC(即永远不会运行的 GC)对 Python 完全有效。您无法保证 GC 将永远运行。而gc.disable
可以在大多数 Python 实现中禁用 GC。
在 GC 进行任何清理之前,我设法用完了可用的连接。所以是的,如果您不想突然发现连接丢失,您应该打电话关闭。以上是关于我应该在 urllib.urlopen() 之后调用 close() 吗?的主要内容,如果未能解决你的问题,请参考以下文章
urllib2.urlopen() 与 urllib.urlopen() - urllib2 在 urllib 工作时抛出 404!为啥?
使用 urllib2.urlopen 时如何访问包含重定向的原始响应标头
如何使用urllib2.urlopen检查(不绕过)SSL证书?