62

(编辑:也许我对这个错误的含义有误。这是否表明我的 CLIENT 的连接池已满?或者 SERVER 的连接池已满,这是我的客户端给出的错误?)

http我正在尝试使用 pythonthreadingrequests模块同时发出大量请求。我在日志中看到此错误:

WARNING:requests.packages.urllib3.connectionpool:HttpConnectionPool is full, discarding connection:

我可以做些什么来增加请求的连接池的大小?

4

4 回答 4

128

这应该可以解决问题:

import requests.adapters

session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
response = session.get("/mypage")
于 2013-09-17T09:21:42.190 回答
29

注意:仅当您无法控制连接池的构造时才使用此解决方案(如@Jahaja 的回答中所述)。

问题是urllib3按需创建池。urllib3.connectionpool.HTTPConnectionPool它不带参数地调用类的构造函数。课程注册在urllib3 .poolmanager.pool_classes_by_scheme. 诀窍是用具有不同默认参数的类替换这些类:

def patch_http_connection_pool(**constructor_kwargs):
    """
    This allows to override the default parameters of the 
    HTTPConnectionPool constructor.
    For example, to increase the poolsize to fix problems 
    with "HttpConnectionPool is full, discarding connection"
    call this function with maxsize=16 (or whatever size 
    you want to give to the connection pool)
    """
    from urllib3 import connectionpool, poolmanager

    class MyHTTPConnectionPool(connectionpool.HTTPConnectionPool):
        def __init__(self, *args,**kwargs):
            kwargs.update(constructor_kwargs)
            super(MyHTTPConnectionPool, self).__init__(*args,**kwargs)
    poolmanager.pool_classes_by_scheme['http'] = MyHTTPConnectionPool

然后您可以调用设置新的默认参数。确保在建立任何连接之前调用它。

patch_http_connection_pool(maxsize=16)

如果您使用 https 连接,您可以创建类似的功能:

def patch_https_connection_pool(**constructor_kwargs):
    """
    This allows to override the default parameters of the
    HTTPConnectionPool constructor.
    For example, to increase the poolsize to fix problems
    with "HttpSConnectionPool is full, discarding connection"
    call this function with maxsize=16 (or whatever size
    you want to give to the connection pool)
    """
    from urllib3 import connectionpool, poolmanager

    class MyHTTPSConnectionPool(connectionpool.HTTPSConnectionPool):
        def __init__(self, *args,**kwargs):
            kwargs.update(constructor_kwargs)
            super(MyHTTPSConnectionPool, self).__init__(*args,**kwargs)
    poolmanager.pool_classes_by_scheme['https'] = MyHTTPSConnectionPool
于 2014-03-07T15:06:21.620 回答
4

Jahaja 的回答已经为您的问题提供了推荐的解决方案,但它没有回答正在发生的事情,或者正如您所问的,这个错误意味着什么

有关这方面的一些非常详细的信息在urllib3官方文档中,包requests在后台使用来实际执行其请求。以下是您问题的相关部分,添加了我自己的一些注释并省略了代码示例,因为requests有不同的 API:

该类会根据需要自动处理为每个主机PoolManager创建实例。ConnectionPool默认情况下,它会保留最多 10 个 ConnectionPool 实例[注意:pool_connections在 中requests.adapters.HTTPAdapter(),它具有相同的默认值 10]。如果您向许多不同的主机发出请求,则增加此数量可能会提高性能

但是,请记住,这确实会增加内存和套接字消耗。

同样,ConnectionPool 类保留了一个单独的HTTPConnection实例池。这些连接在单个请求期间使用,并在请求完成时返回到池中。默认情况下,只会保存一个连接以供重复使用[注意:pool_maxsize在 中HTTPAdapter(),并且 requests 将默认值从 1 更改为 10]。如果您同时向同一主机发出许多请求,则增加此数量可能会提高性能

ConnectionPool 的池化行为与 PoolManager 不同。默认情况下,如果发出新请求并且池中没有空闲连接,则将创建一个新连接。但是,如果存在多个连接,则不会保存此连接maxsize。这意味着 maxsize 不会确定可以打开到特定主机的最大连接数,只是要保留在池中的最大连接数。但是,如果您指定block=True [注意:pool_block在 中可用HTTPAdapter()] ,则最多可以有 maxsize 个连接打开到特定主机

鉴于此,您的情况如下:

  • 提到的所有池都是 CLIENT 池。您(或requests)无法控制任何服务器连接池
  • 该警告是关于HttpConnectionPool,即同时连接到同一主机的数量,因此您可以增加pool_maxsize以匹配您用来消除警告的工作人员/线程的数量。
  • 请注意requests无论. pool_maxsize如果你有 100 个线程,它将打开 100 个连接。但使用默认值时,池中只会保留 10 个以供以后重用,完成请求后将丢弃 90 个。
  • 因此,更大的通过重用连接而不是通过增加并发来提高单个主机pool_maxsize的性能。
  • 如果您正在处理多个主机,那么您可能会改为更改pool_connections。默认值已经是 10,因此如果您的所有请求都针对同一目标主机,则增加它不会对性能产生任何影响(但会增加使用的资源,如上述文档中所述)
于 2021-03-17T11:42:00.717 回答
0

如果有人需要用 Python Zeep 来做这件事,并且想花一点时间来弄清楚这里是一个快速的方法:

from zeep import Client
from requests import adapters as request_adapters

soap = "http://example.com/BLA/sdwl.wsdl"
wsdl_path = "http://example.com/PATH/TO_WSLD?wsdl"
bind = "Binding"
client = Client(wsdl_path)  # Create Client

# switch adapter
session = client.transport.session
adapter = request_adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10)
# mount adapter
session.mount('https://', adapter)
binding = '{%s}%s' % (soap, bind)

# Create Service
service = client.create_service(binding, wsdl_path.split('?')[0])

基本上应该在创建服务之前创建连接

答案实际上是从一个已关闭问题的 python-zeep Repo 中获取的,作为参考,我将添加它 -->这里

于 2022-01-13T16:29:31.373 回答