在线程中,改变Python的 "request "模块的连接池大小

65 人关注

(编辑:也许我搞错了这个错误的意思。 这是否表明我的客户机的连接池已满?还是服务器的连接池已满,而这是我的客户机所得到的错误?)

我试图使用python的 http requests 模块来并发大量的【替换代码】请求。 我在日志中看到这个错误。

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

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

python
multithreading
python-requests
request
connection-pooling
Skip Huffman
Skip Huffman
发布于 2013-08-27
4 个回答
Jahaja
Jahaja
发布于 2022-01-14
已采纳
0 人赞同

This should do the trick:

import requests.adapters
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
response = session.get("/mypage")
    
这对我来说是有效的。它应该被标记为正确答案。
lfk
在用 https 替换了 http 之后,这就成功了。此外,我认为 pool_connections 是不必要的。
lfk
每个会话都有自己的连接池,还是多个会话共享一个连接池?
@JohnStrood查看了 sess.adapters['https://']._pool_maxsize session.adapters['https://']._pool_connections 。似乎它们都是默认等于10的。
@JohnStrood: 一个更符合要求的方法,不依赖任何 "私有 "属性,对一个给定的URL进行检查,将是 sess.get_adapter(url).poolmanager.connection_pool_kw['maxsize']
Michael_Scharf
Michael_Scharf
发布于 2022-01-14
0 人赞同

Note: 只有在你不能控制连接池的构建时才使用这个解决方案(如@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
    
Requests有一个内置的API来提供ConnectionPool构造函数参数,修补构造函数是不必要的。(参见@Jahaja的回答)。
这取决于上下文。如果你能控制HTTPAdapter的创建,使用构造函数是正确的解决方案。但有些情况下,连接池被初始化在某些框架或库中的某个地方。在这些情况下,你可以修补库或修补连接池构造函数,正如我上面所描述的。
我对我的解决方案做了一个澄清。
是的,它可能是一个不同问题的答案,但这是我在搜索类似问题时发现的问题。 HttpConnectionPool is full, discarding connection python 。但这个解决方案并没有帮助我,因为我的连接池是由一些库(在我的例子中是pyes)创建的。
@shazow,首先 ConnectionPool 只是一个基类,你唯一能做的就是对其进行子类化,但不能通过 池的最大尺寸 或任何其他(只有主机和端口)。 其次,最初的问题正好是针对 requests/urllib3 库,因为它是处理HTTP的最好的Pythonic解决方案,所以我没有看到任何禁止在这些库的背景下专门回答的问题
MestreLion
MestreLion
发布于 2022-01-14
0 人赞同

Jahaja的回答 已经给出了 recommended solution 你的问题,但它并没有回答发生了什么,或者如你所问。 这个错误意味着什么 .

关于这方面的一些非常详细的信息,见于 urllib3 官方文件 替换代码1】使用的包在引擎盖下实际执行其请求。以下是与你的问题相关的部分,添加了一些我自己的注释,并略去了代码例子,因为 requests 有不同的API。

这个 PoolManager 类会根据需要自动处理为每个主机创建 ConnectionPool 实例。默认情况下,它将保持最多10个ConnectionPool实例。 [注:这就是 requests.adapters.HTTPAdapter() 中的 pool_connections ,它的默认值也是10】。] .如果你向许多不同的主机发出请求,增加这个数字可能会提高性能。

然而,请记住,这确实增加了内存和插座的消耗。

同样地,ConnectionPool类保存了一个单独的 HTTPConnection 实例池。这些连接在一个单独的请求中被使用,并在请求完成后返回到池中。默认情况下,只有一个连接会被保存下来以便再次使用 [注:这是 HTTPAdapter() 中的 pool_maxsize ,要求将默认值从1改为10】。] .如果你同时向同一主机发出许多请求,增加这个数字可能会提高性能。

ConnectionPool的池化行为与PoolManager不同。默认情况下,如果一个新的请求被提出,而池子里没有空闲的连接,那么一个新的连接将被创建。然而,如果存在超过 maxsize 的连接,这个连接将不会被保存。这意味着maxsize并不决定可以打开到某个特定主机的最大连接数,只是决定在池中保留的最大连接数。然而,如果你指定了 block=True 的话 [Note: Available as pool_block in HTTPAdapter() ] 那么在一个特定的主机上,最多只能有最大尺寸的连接打开。

鉴于此,你的情况是这样的。

  • All pools mentioned are CLIENT pools. You (or requests ) have no control over any server connection pools
  • That warning is about HttpConnectionPool , i.e, the number of simultaneous connections made to the same host , so you could increase pool_maxsize to match the number of workers/threads you're using to get rid of the warning.
  • Note that requests is already opening as many simultaneous connections as you ask for, regardless of pool_maxsize . If you have 100 threads, it will open 100 connections. But with the default value only 10 of them will be kept in the pool for later reuse, and 90 will be discarded after completing the request.
  • Thus, a larger pool_maxsize increases performance to a single host by reusing connections , not by increasing concurrency.
  • If you're dealing with multiple hosts , then you might change pool_connections instead. The default is 10 already, so if all your requests are to the same target host, increasing it will not have any effect on performance (but it will increase the resources used, as said in above documentation)
  • Federico Baù
    Federico Baù
    发布于 2022-01-14
    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