【问题标题】:python requests module and connection reusepython请求模块和连接重用
【发布时间】:2014-09-12 11:30:36
【问题描述】:

我正在使用 python 的 requests 模块进行 HTTP 通信,我想知道如何重用已经建立的 TCP 连接? requests 模块是无状态的,如果我对同一个 URL 重复调用 get,它不会每次都创建一个新的连接吗?

谢谢!!

【问题讨论】:

标签: python python-requests keep-alive


【解决方案1】:

requests.getrequests.post 这样的全局函数会在每次调用时创建requests.Session 实例。使用这些功能建立的连接不能重复使用,因为您无法访问自动创建的会话并将其连接池用于后续请求。如果您只需要执行几个请求,则可以使用这些功能。否则,您需要自己管理会话。

这是使用全局get 函数和会话时requests 行为的快速显示。

准备,与问题无关:

>>> import logging, requests, timeit
>>> logging.basicConfig(level=logging.DEBUG, format="%(message)s")

看,每次调用get都会建立一个新的连接:

>>> _ = requests.get("https://www.wikipedia.org")
Starting new HTTPS connection (1): www.wikipedia.org
>>> _ = requests.get("https://www.wikipedia.org")
Starting new HTTPS connection (1): www.wikipedia.org

但如果您在后续调用中使用相同的会话,则连接会被重用:

>>> session = requests.Session()
>>> _ = session.get("https://www.wikipedia.org")
Starting new HTTPS connection (1): www.wikipedia.org
>>> _ = session.get("https://www.wikipedia.org")
>>> _ = session.get("https://www.wikipedia.org")
>>> _ = session.get("https://www.wikipedia.org")

性能:

>>> timeit.timeit('_ = requests.get("https://www.wikipedia.org")', 'import requests', number=100)
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
...
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
Starting new HTTPS connection (1): www.wikipedia.org
52.74904417991638
>>> timeit.timeit('_ = session.get("https://www.wikipedia.org")', 'import requests; session = requests.Session()', number=100)
Starting new HTTPS connection (1): www.wikipedia.org
15.770191192626953

当您重用会话(以及会话的连接池)时,工作速度会更快。

【讨论】:

  • 可能是requests 模块可用的最佳答案,但它仍然不令人满意,因为它将连接重用与会话处理混为一谈。仅仅因为我想在请求之间共享连接并不意味着我想共享 cookie 等。最好是像 requests.enable_pooling() 这样的选项,以透明地启用由主机名和端口键入的池(因为接受的答案错误地建议是默认值) .
  • 你说得有道理,大卫·翁加罗。但是,这是对有关特定库的特定问题的回答。答案反映了库的实现。你的建议超出了这个问题的范围。我认为在请求库错误跟踪器中讨论您的建议是一个更好的地方。
【解决方案2】:

requests 模块是无状态的,如果我对同一个 URL 重复调用 get,它不会每次都创建一个新连接吗?

requests 模块不是无状态的;如果您选择这样做,它只是让您忽略状态并有效地使用全局单例状态。*

并且它(或者,更确切地说,一个底层库,urllib3)维护一个由(主机名,端口)对作为键控的连接池,所以它通常会神奇地重用一个连接,如果可以的话。

正如the documentation 所说:

好消息——感谢 urllib3,keep-alive 是 100% 自动的 在一个会话中!您在会话中提出的任何请求都将 自动重用适当的连接!

请注意,连接只会释放回池中以供重复使用 读取所有身体数据后;请务必将stream 设置为 False 或读取Response 对象的content 属性。

那么,“如果可以的话”是什么意思?正如上面的文档所暗示的那样,如果您保持流式响应对象处于活动状态,那么它们的连接显然不能被重用。

另外,连接池实际上是一个有限缓存,而不是无限的,所以如果您发送大量连接并且其中两个连接到同一台服务器,您将不会总是重用连接,只是经常。但通常,这才是你真正想要的。


* 这里相关的特定状态是transport adapter。每个会话都有一个传输适配器。您可以手动指定适配器,也可以指定全局默认值,或者您可以只使用默认的全局默认值,它基本上只是包装了一个 urllib3.PoolManager 来管理其 HTTP 连接。有关更多信息,请阅读文档。

【讨论】:

  • 非常感谢您的详细回复;这真的很有帮助。我还有一个问题。上述文档中的“会话”是什么?我通读了文档,实际上有一个 Session 对象。我通读了“请求”代码,并为每个请求创建了一个 Session 对象。因此,如果仅在 Session 中重用连接,那么我不确定如何在两个“get”调用之间重用连接。
  • @gmemon:抱歉,措辞不好。我的意思是组成全局状态的适配器集合,在这种情况下特别是HTTPAdapter(它是拥有urllib3.PoolManager 的东西)。我不知道正确的术语是什么,但“会话”显然是一个糟糕的选择。我会编辑答案。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 2019-03-23
  • 2011-10-23
  • 1970-01-01
相关资源
最近更新 更多