【发布时间】:2014-09-12 11:30:36
【问题描述】:
我正在使用 python 的 requests 模块进行 HTTP 通信,我想知道如何重用已经建立的 TCP 连接? requests 模块是无状态的,如果我对同一个 URL 重复调用 get,它不会每次都创建一个新的连接吗?
谢谢!!
【问题讨论】:
标签: python python-requests keep-alive
我正在使用 python 的 requests 模块进行 HTTP 通信,我想知道如何重用已经建立的 TCP 连接? requests 模块是无状态的,如果我对同一个 URL 重复调用 get,它不会每次都创建一个新的连接吗?
谢谢!!
【问题讨论】:
标签: python python-requests keep-alive
像requests.get 或requests.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() 这样的选项,以透明地启用由主机名和端口键入的池(因为接受的答案错误地建议是默认值) .
requests 模块是无状态的,如果我对同一个 URL 重复调用 get,它不会每次都创建一个新连接吗?
requests 模块不是无状态的;如果您选择这样做,它只是让您忽略状态并有效地使用全局单例状态。*
并且它(或者,更确切地说,一个底层库,urllib3)维护一个由(主机名,端口)对作为键控的连接池,所以它通常会神奇地重用一个连接,如果可以的话。
正如the documentation 所说:
好消息——感谢 urllib3,keep-alive 是 100% 自动的 在一个会话中!您在会话中提出的任何请求都将 自动重用适当的连接!
请注意,连接只会释放回池中以供重复使用 读取所有身体数据后;请务必将
stream设置为False或读取Response对象的content属性。
那么,“如果可以的话”是什么意思?正如上面的文档所暗示的那样,如果您保持流式响应对象处于活动状态,那么它们的连接显然不能被重用。
另外,连接池实际上是一个有限缓存,而不是无限的,所以如果您发送大量连接并且其中两个连接到同一台服务器,您将不会总是重用连接,只是经常。但通常,这才是你真正想要的。
* 这里相关的特定状态是transport adapter。每个会话都有一个传输适配器。您可以手动指定适配器,也可以指定全局默认值,或者您可以只使用默认的全局默认值,它基本上只是包装了一个 urllib3.PoolManager 来管理其 HTTP 连接。有关更多信息,请阅读文档。
【讨论】:
HTTPAdapter(它是拥有urllib3.PoolManager 的东西)。我不知道正确的术语是什么,但“会话”显然是一个糟糕的选择。我会编辑答案。感谢您指出这一点。