urllib2和httplib线程安全吗?

20 投票
1 回答
10913 浏览
提问于 2025-04-16 16:37

我想了解一下 urllib2httplib 的线程安全性。官方文档(http://docs.python.org/library/urllib2.htmlhttp://docs.python.org/library/httplib.html)对此没有任何说明,甚至连“线程”这个词都没有提到……

更新

好的,它们默认情况下不是线程安全的。那么,要让它们线程安全需要做些什么,或者有没有什么情况可以让它们线程安全呢?我问这个是因为似乎

  • 在每个线程中使用独立的 OpenerDirector
  • 不在多个线程之间共享 HTTP 连接

就足以安全地在线程中使用这些库。类似的使用场景在问题 urllib2 和 cookielib 的线程安全性 中也有提到。

1 个回答

42

httpliburllib2不安全的,在多线程环境下使用时可能会出问题。

urllib2 不提供对一个全局(共享的)OpenerDirector 对象的安全访问,这个对象是通过 urllib2.urlopen() 来使用的。

同样,httplib 也不提供对 HTTPConnection 对象的安全访问(也就是说,它没有使用一个线程安全的连接池),所以在多个线程之间共享 HTTPConnection 对象是不安全的。

如果你需要线程安全的功能,我建议使用 httplib2urllib3 作为替代方案。

一般来说,如果一个模块的文档中没有提到线程安全,我会认为它是不安全的。你可以查看模块的源代码来确认这一点。

在查看源代码以判断一个模块是否线程安全时,可以先找找 threadingmultiprocessing 模块中的线程同步工具,或者查看 queue.Queue 的使用情况。

更新

这里有一段来自 urllib2.py(Python 2.7.2)的相关源代码片段:

_opener = None
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
    global _opener
    if _opener is None:
        _opener = build_opener()
    return _opener.open(url, data, timeout)

def install_opener(opener):
    global _opener
    _opener = opener

当多个线程同时调用 install_opener()urlopen() 时,会出现明显的竞争条件。

另外,注意用 Request 对象作为 url 参数调用 urlopen() 可能会改变这个 Request 对象(具体可以查看 OpenerDirector.open() 的源代码),所以在多个线程中同时使用一个共享的 Request 对象调用 urlopen() 是不安全的。

总的来说,如果满足以下条件,urlopen() 是线程安全的:

  • 不能从其他线程调用 install_opener()
  • 作为 url 参数使用的是一个非共享的 Request 对象或字符串。

撰写回答