python请求模块和连接重用

gme*_*mon 19 python keep-alive

我正在使用python的HTTP通信请求模块,我想知道如何重用已经建立的TCP连接?请求模块是无状态的,如果我反复调用get获取相同的URL,那么每次都会创建一个新的连接吗?

谢谢!!

Dmy*_*huk 53

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

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

准备工作,与问题无关:

>>> import logging, requests, timeit
>>> logging.basicConfig(level=logging.DEBUG, format="%(message)s")
Run Code Online (Sandbox Code Playgroud)

请参阅每次调用时建立的新连接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
Run Code Online (Sandbox Code Playgroud)

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

>>> 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")
Run Code Online (Sandbox Code Playgroud)

性能:

>>> 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
Run Code Online (Sandbox Code Playgroud)

重用会话(以及会话的连接池)时,工作速度会快得多.

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

aba*_*ert 6

请求模块是无状态的,如果我反复调用get获取相同的URL,那么每次都会创建一个新的连接吗?

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

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

正如文件所说:

好消息 - 感谢urllib3,keep-alive在会话中100%自动!您在会话中发出的任何请求都将自动重用相应的连接!

请注意,只有在读取了所有正文数据后,才会将连接释放回池中以供重用; 一定要设置或者streamFalse或读取content的财产Response对象.

那么,"如果可以"是什么意思呢?正如上面的文档所暗示的那样,如果你保持流式响应对象存活,它们的连接显然不能被重用.

此外,连接池确实是一个有限的缓存,而不是无限的,所以如果您的垃圾邮件了一吨的连接,其中两个是在同一台服务器,你不会总是重复使用的连接,只需经常.但通常,这就是你真正想要的.


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

  • 非常感谢您的详细回复;这真的很有帮助。我还有一个问题。上述文档中的“会话”是什么?我通读了文档,实际上有一个 Session 对象。我通读了“请求”代码,并为每个请求创建了一个 Session 对象。因此,如果连接仅在会话中重用,那么我不确定如何在两个“get”调用之间重用连接。 (2认同)