Могу ли я изменить размер пула соединений для модуля запросов Python?

(edit: Возможно, я ошибаюсь в том, что означает эта ошибка. Означает ли это, что пул соединений на моем КЛИЕНТЕ заполнен? или пул соединений на СЕРВЕРЕ заполнен, и это ошибка, которую выдает моему клиенту?)

Я пытаюсь выполнить большое количество http запросов одновременно, используя модули python threading и requests. Я вижу эту ошибку в журналах:

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

Что я могу сделать, чтобы увеличить размер пула соединений для запросов?


person Skip Huffman    schedule 27.08.2013    source источник


Ответы (3)


Это должно помочь:

import requests.adapters

session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
response = session.get("/mypage")
person Jahaja    schedule 17.09.2013
comment
У меня это работает. Он должен быть отмечен как правильный ответ. - person reish; 21.01.2014
comment
Это сработало после замены http на https. Также я считаю pool_connections ненужным. - person lfk; 05.04.2018
comment
У каждого сеанса есть собственный пул подключений или несколько сеансов используют общий пул подключений? - person lfk; 05.04.2018
comment
@lfk, вероятно, можно поделиться им, добавив один экземпляр адаптера к нескольким сеансам. Но, вероятно, это не лучшая идея. - person skhalymon; 07.07.2020
comment
Как я могу проверить размер текущего пула перед его увеличением? - person John Strood; 10.09.2020
comment
@JohnStrood, посмотри sess.adapters['https://']._pool_maxsize и session.adapters['https://']._pool_connections. Похоже, что оба они по умолчанию равны 10. - person Andrey Semakin; 29.09.2020
comment
Обратите внимание, что (pool_connections=100, pool_maxsize=100) - очень высокие значения. Вы должны адаптировать их к своему фактическому сценарию, учитывая количество различных хостов, к которым вы подключаетесь, и количество используемых вами рабочих потоков. - person MestreLion; 17.03.2021
comment
@JohnStrood: более совместимый способ, не полагаясь на какие-либо частные атрибуты, проверить его для данного URL-адреса будет sess.get_adapter(url).poolmanager.connection_pool_kw['maxsize']. - person MestreLion; 17.03.2021

Примечание. Используйте это решение, только если вы не можете контролировать создание пула соединений (как описано в ответе @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
person Michael_Scharf    schedule 07.03.2014
comment
Requests имеет встроенный API для предоставления параметров конструктора ConnectionPool, исправление конструктора не требуется. (См. Ответ @Jahaja.) - person shazow; 11.05.2014
comment
Это зависит от контекста. Если у вас есть контроль над созданием HTTPAdapter, использование конструктора - правильное решение. Но бывают случаи, когда пул соединений инициализируется где-то глубоко похороненным в каком-то фреймворке или библиотеке. В таких случаях вы можете исправить библиотеку или конструктор пула соединений, как я описал выше. - person Michael_Scharf; 12.05.2014
comment
Я добавил уточнение к своему решению. - person Michael_Scharf; 12.05.2014
comment
Я полагаю, что это ценный справочник, но, честно говоря, он отвечает на другой вопрос. :) Исходный вопрос касается именно того, как изменить это в запросах, а не другой гипотетической библиотеке. - person shazow; 12.05.2014
comment
Да, это может быть ответ на другой вопрос, но это вопрос, который я нашел, когда искал что-то вроде: HttpConnectionPool is full, discarding connection python. Но решение мне не помогло, потому что мой пул соединений создается какой-то библиотекой (в моем случае это pyes). - person Michael_Scharf; 13.05.2014
comment
@Michael_Scharf находили ли вы способ отключить это предупреждение в случае отсутствия контроля над кодом / библиотекой? - person sirvon; 20.03.2015
comment
@shazow, во-первых, ConnectionPool - это просто базовый класс, и единственное, что вы можете сделать, это создать его подкласс, но не передавать pool_maxsize или какой-либо другой (только хост и порт). А во-вторых, первоначальный вопрос был адресован именно библиотеке requests / urllib3, потому что это лучшее питоническое решение для обработки HTTP, поэтому я не вижу никаких запретов, отвечающих конкретно в контексте этих библиотек. - person Alex-Bogdanov; 19.07.2017
comment
@Michael_Scharf Мне было интересно, как можно получить размер существующего пула соединений? Перед увеличением пула. - person John Strood; 10.09.2020

Ответ Джахаджи уже дает рекомендуемое решение вашей проблемы, но оно не отвечает на то, что происходит, или, как вы спросили, что означает эта ошибка .

Некоторая очень подробная информация об этом находится в urllib3 официальной документации < / a>, пакет requests использует «под капотом» для фактического выполнения своих запросов. Вот соответствующие части вашего вопроса, добавив несколько собственных заметок и опуская примеры кода, поскольку requests имеет другой API:

Класс PoolManager автоматически обрабатывает создание ConnectionPool экземпляров для каждого хоста по мере необходимости. По умолчанию он сохраняет максимум 10 экземпляров ConnectionPool [Примечание. Это pool_connections в requests.adapters.HTTPAdapter(), и у него такое же значение по умолчанию, равное 10]. Если вы делаете запросы к разным хостам, это может повысить производительность, увеличив это число.

Однако имейте в виду, что это увеличивает потребление памяти и сокетов.

Точно так же класс ConnectionPool хранит пул отдельных HTTPConnection экземпляров. Эти соединения используются во время индивидуального запроса и возвращаются в пул по завершении запроса. По умолчанию только одно соединение будет сохранено для повторного использования [Примечание. Это pool_maxsize в HTTPAdapter(), и запросы изменяют значение по умолчанию с 1 на 10]. Если вы делаете много запросов к одному и тому же хосту одновременно, это может повысить производительность, увеличив это число.

Поведение пула для ConnectionPool отличается от PoolManager. По умолчанию, если сделан новый запрос и в пуле нет свободного соединения, будет создано новое соединение. Однако это соединение не будет сохранено, если существует более maxsize соединений. Это означает, что maxsize не определяет максимальное количество подключений, которые могут быть открыты для конкретного хоста, а только максимальное количество подключений, которые необходимо сохранить в пуле. Однако, если вы укажете block=True [Примечание: доступно как pool_block в HTTPAdapter()], то с определенным хостом может быть открыто не более максимального размера соединений.

Учитывая это, вот что произошло в вашем случае:

  • Все упомянутые пулы являются пулами КЛИЕНТА. Вы (или requests) не контролируете какие-либо пулы соединений с серверами
  • Это предупреждение касается HttpConnectionPool, то есть количества одновременных подключений к тому же хосту, поэтому вы можете увеличить pool_maxsize, чтобы оно соответствовало количеству рабочих / потоков, которые вы используете, чтобы избавиться от предупреждения.
  • Обратите внимание, что requests уже открывает столько одновременных подключений, сколько вы запрашиваете, независимо от pool_maxsize. Если у вас 100 потоков, он откроет 100 подключений. Но со значением по умолчанию только 10 из них будут сохранены в пуле для последующего повторного использования, а 90 будут отброшены после выполнения запроса.
  • Таким образом, увеличение pool_maxsize увеличивает производительность одного хоста за счет повторного использования соединений, а не за счет увеличения параллелизма.
  • Если вы имеете дело с несколькими хостами, вы можете вместо этого изменить pool_connections. По умолчанию уже установлено 10, поэтому, если все ваши запросы относятся к одному и тому же целевому хосту, его увеличение не повлияет на производительность (но увеличит используемые ресурсы, как указано в документации выше).
person MestreLion    schedule 17.03.2021