1

考虑这个向 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 文档的这一部分建议在Client向同一个 URL 发出多个请求时使用 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将确保:

...客户端实例使用 HTTP 连接池。这意味着当您向同一主机发出多个请求时,客户端将重用底层 TCP 连接,而不是为每个请求重新创建一个。

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

4

1 回答 1

1

这样做有什么好处还是有更好的方法?

httpx.Client不,以您展示的方式使用没有任何优势。事实上,httpx.<method>API,例如httpx.get完全一样的事情

Client“池”是HTTPTransport默认情况下由持有的传输管理器的一项功能。传输在Client初始化时创建并存储为实例属性self._transport

创建一个新Client实例意味着一个新HTTPTransport实例,传输实例有自己的 TCP 连接池。Client通过每次创建一个新实例并且只使用一次,与httpx.get直接使用 eg 相比没有任何好处。

那可能没问题!连接池是对为每个请求创建新 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 繁重的工作负载,您可以通过并行执行结果来做得更好,例如使用httpx.AsyncClient.

于 2022-02-08T16:27:25.473 回答