1. 程式人生 > >關於python Connection pool is full, discarding connection

關於python Connection pool is full, discarding connection

問題復現

本地新建request.Session, 多執行緒開啟url併發較高時, 出現以下報錯:

requests.packages.urllib3.connectionpool:Connection pool is full, discarding connection

測試程式碼

def test_pool_max_size():
    # 測試 pool_maxsize 對多執行緒訪問的影響
    def thread_get(url):
        s.get(url)

    s = requests.Session()
    s.mount('https://', HTTPAdapter(pool_connections=1, pool_maxsize=1))
    ts = []
    for _ in range(2):
        t = Thread(target=thread_get, args=('https://www.ask.com',))
        ts.append(t)
        t.start()
    for t in ts:
        t.join()

程式碼分析

HTTPAdapter用於對指定網址的連線管理, 引數包含pool_connections=1, pool_maxsize=1.

在HTTPAdapter中的init中會新建poolmanager

    def __init__(self, pool_connections=DEFAULT_POOLSIZE,pool_maxsize=DEFAULT_POOLSIZE ...):
        ...
        self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)

    def init_poolmanager(self, connections, maxsize ...):
        ...
        self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,
                                       block=block, strict=True, **pool_kwargs)

在PoolManager中num_pools也就是pool_connections用於構造RecentlyUsedContainer容器, 該容器用於儲存最近使用的HTTPConnectionPool/HTTPSConnectionPool. HTTPConnectionPool/HTTPSConnectionPool管理指定(url, port)的所有連線. 

    def __init__(self, num_pools=10 ...):
        ...
        self.pools = RecentlyUsedContainer(num_pools,
                                           dispose_func=lambda p: p.close())

HTTPConnectionPool/HTTPSConnectionPool也有一個pool, 是LifoQueue容器, 由pool_maxsize引數構造, 儲存的是HTTPConnection. HTTPConnection儲存與伺服器的socket連線.

pool_connections, pool_maxsize解析

pool_connections在poolmanager中限制快取中不同url對應的HTTPConnectionPool/HTTPSConnectionPool數目. 

pool_maxsize在HTTPConnectionPool/HTTPSConnectionPool中限制快取中同一個url連線的數目. 單執行緒時執行時, 只會同時存在一個連線, 不會出現連線數過多的問題. 多執行緒時, 當同一網址的url請求數量大於pool_maxsize時, 發起url呼叫時不會報錯, 在請求返回時, 會將連線放入HTTPConnectionPool/HTTPSConnectionPool中的LifoQueue, 當併發請求數量大於pool_maxsize時, LifoQueue不夠放入所有的請求, 就會報錯Connection pool is full, discarding connection.