Python & HTTPX:httpx 客户端的连接池是如何工作的?

Python & HTTPX: How does httpx client's connection pooling work?

考虑这个向 API 端点发出简单 GET 请求的函数:

import httpx 

def check_status_without_session(url : str) -> int:
    response = httpx.get(url)
    return response.status_code

运行 这个函数会在每次函数 check_status_without_session 被调用时打开一个新的 TCP 连接。现在,HTTPX 文档的 this 部分建议在对同一个 URL 发出多个请求时使用 Client API。以下函数执行此操作:

import httpx

def check_status_with_session(url: str) -> int:
    with httpx.Client() as client:
        response = client.get(url)
        return response.status_code

根据文档使用 Client 将确保:

... a Client instance uses HTTP connection pooling. This means that when you make several requests to the same host, the Client will reuse the underlying TCP connection, instead of recreating one for every single request.

我的问题是,在第二种情况下,我将 Client 上下文管理器包装在一个函数中。如果我使用相同的 URL 多次调用 check_status_with_session,难道不是每次调用该函数时都会创建一个新的连接池吗?这意味着它实际上并没有重用连接。由于函数堆栈在函数执行后被销毁,因此 Client 对象也应该被销毁,对吧? 这样做有什么好处或者有更好的方法吗?

Is there any advantage in doing it like this or is there a better way?

不,按照您展示的方式使用 httpx.Client 没有任何优势。事实上 httpx.<method> API,例如httpx.get, exactly the same thing!

“池”是 Client 持有的传输管理器的一个特征,即 HTTPTransport by default. The transport is created at Client initialisation time and stored as the instance property self._transport

创建一个新的Client实例意味着一个新的HTTPTransport实例,传输实例有自己的TCP连接池。通过每次创建一个新的 Client 实例并只使用它一次,您不会比使用例如httpx.get直接。

这可能没问题!连接池是对为每个请求创建新的 TCP 连接的一种优化。您的应用程序可能不需要优化,它的性能可能已经足以满足您的需求。

如果您在紧密循环中向同一个端点发出许多请求,在循环的上下文中进行迭代 可能会 为您带来一些吞吐量收益,例如

with httpx.Client(base_url="https://example.com") as client:
    results = [client.get(f"/api/resource/{idx}") for idx in range(100)]

对于这样的 I/O-heavy 工作负载,您可以通过并行执行结果来做得更好,例如使用 httpx.AsyncClient.