我应该在 urllib.urlopen() 之后调用 close() 吗?

Posted

技术标签:

【中文标题】我应该在 urllib.urlopen() 之后调用 close() 吗?【英文标题】:should I call close() after urllib.urlopen()? 【发布时间】:2021-11-08 05:47:46 【问题描述】:

我是 Python 新手,正在阅读别人的代码:

urllib.urlopen() 后面应该跟urllib.close() 吗?否则,会泄漏连接,对吗?

【问题讨论】:

【参考方案1】:

close 方法必须在 urllib.urlopenresult 上调用,而不是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/…【参考方案2】:

就像@Peter 所说,超出范围打开的 URL 将有资格进行垃圾收集。

不过,还要注意urllib.py 定义:

 def __del__(self):
        self.close()

这意味着当该实例的引用计数为零时,它的__del__ 方法将被调用,因此它的close 方法也将被调用。引用计数达到零的最“正常”方式是简单地让实例超出范围,但没有什么严格阻止您尽早使用显式 del x(但是它不直接调用 __del__ 而只是将引用计数减一)。

明确关闭你的资源肯定是一种很好的方式——尤其是当你的应用程序冒着使用过多上述资源的风险时——但是如果你不这样做,Python 自动为你清理做一些有趣的事情,比如维护(循环?)对不再需要的实例的引用。

【讨论】:

然而,有可能超出垃圾收集器——我有过创建文件句柄比关闭它们更快的情况[但是显式的 gc.collect() 调用或 @ 987654329@,收拾东西]。【参考方案3】:

严格来说,这是真的。但实际上,一旦(如果)urllib 超出范围,自动垃圾收集器将关闭连接。

【讨论】:

这在 Python 的某些实现中是正确的,但是 Python 语言不保证对象一旦超出范围就会关闭。参看。 jython @gnibbler 这个答案的作者没有说它会发生只要它就会发生。 @Piotr,但如果我有一个循环打开 url 并且 GC 没有足够快地获取它们,程序可能会崩溃。这是一种非常草率的做事方式,不属于生产代码。 no-op GC(即永远不会运行的 GC)对 Python 完全有效。您无法保证 GC 将永远运行。而gc.disable 可以在大多数 Python 实现中禁用 GC。 在 GC 进行任何清理之前,我设法用完了可用的连接。所以是的,如果您不想突然发现连接丢失,您应该打电话关闭。【参考方案4】:

您基本上确实需要在使用 IronPython 时显式关闭您的连接。超出范围的自动关闭依赖于垃圾收集。我遇到了一种情况,即垃圾收集没有运行很长时间,以至于 Windows 用完了套接字。我以高频率轮询网络服务器(即与 IronPython 一样高,并且连接允许,~7Hz)。我可以看到“已建立的连接”(即正在使用的套接字)在 PerfMon 上不断上升。解决方案是在每次调用urlopen 后调用gc.collect()

【讨论】:

【参考方案5】:

urllib.request 模块使用 HTTP/1.1 并在其 HTTP 请求中包含 Connection:close 标头。

来自官方文档,您可以查看here。

【讨论】:

以上是关于我应该在 urllib.urlopen() 之后调用 close() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

urllib2.urlopen() 与 urllib.urlopen() - urllib2 在 urllib 工作时抛出 404!为啥?

处理 urllib2 的超时? - Python

使用 urllib2.urlopen 时如何访问包含重定向的原始响应标头

如何使用urllib2.urlopen检查(不绕过)SSL证书?

python3中https urlopen()报错的解决方法

Python:从 urllib2.urlopen 调用中获取 HTTP 标头?