我可以更改Python的“请求”模块的连接池大小吗?

时间:2013-08-27 12:55:45

标签: python multithreading request python-requests

(编辑:这个错误意味着我错了。这是否表明我的CLIENT的连接池已满?或者SERVER的连接池已满,这是我的客户端给出的错误?)

我正在尝试使用python httpthreading模块同时发出大量requests个请求。我在日志中看到了这个错误:

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

如何增加请求的连接池大小?

3 个答案:

答案 0 :(得分:79)

这应该可以解决问题:

import requests
sess = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
sess.mount('http://', adapter)
resp = sess.get("/mypage")

答案 1 :(得分:15)

注意:仅当您无法控制连接池的构造时才使用此解决方案(如@ 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

答案 2 :(得分:3)

Jahaja's answer 已经为您的问题提供了 recommended solution,但它没有回答发生了什么,或者如您所问这个错误意味着什么

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

<块引用>

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

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

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

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

鉴于此,您的情况如下:

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