Могу ли я изменить размер пула соединений для модуля Python "запросы"?
(править: Возможно, я ошибаюсь в том, что означает эта ошибка. Указывает ли это, что пул соединений на моем КЛИЕНТЕ заполнен? или пул соединений на СЕРВЕРЕ заполнен, и это ошибка моего клиента?)
Я пытаюсь сделать большое количество http
Запросы одновременно с использованием питона threading
а также requests
модуль. Я вижу эту ошибку в журналах:
WARNING:requests.packages.urllib3.connectionpool:HttpConnectionPool is full, discarding connection:
Что я могу сделать, чтобы увеличить размер пула соединений для запросов?
4 ответа
Это должно сделать трюк:
import requests
sess = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
sess.mount('http://', adapter)
resp = sess.get("/mypage")
Примечание. Используйте это решение, только если вы не можете контролировать построение пула соединений (как описано в ответе @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
Ответ Джахаджи уже дает рекомендуемое решение вашей проблемы, но не отвечает на то, что происходит, или, как вы спросили, что означает эта ошибка .
Некоторая очень подробная информация об этом находится в <tcodeid="9214704">официальная документация</tcodeid="9214704"> , которую пакет использует «под капотом» для фактического выполнения своих запросов. Вот соответствующие части вашего вопроса, добавив несколько собственных заметок и опуская примеры кода, поскольку у них другой API:
В
класс автоматически обрабатывает создание экземпляры для каждого хоста по мере необходимости. По умолчанию в нем будет храниться не более 10 экземпляров ConnectionPool [Примечание. , и имеет то же значение по умолчанию 10] . Если вы делаете запросы к разным хостам, это может улучшить производительность, увеличив это число.Однако имейте в виду, что это увеличивает потребление памяти и сокетов.
Точно так же класс ConnectionPool поддерживает пул отдельных
экземпляры. Эти соединения используются во время индивидуального запроса и возвращаются в пул по завершении запроса. По умолчанию только одно соединение будет сохранено для повторного использования [Примечание: это в, и запросы изменяют значение по умолчанию с 1 на 10] . Если вы делаете много запросов к одному и тому же хосту одновременно, это может улучшить производительность, увеличив это число. Поведение пула для ConnectionPool отличается от PoolManager. По умолчанию, если сделан новый запрос и в пуле нет свободного соединения, будет создано новое соединение. Однако это соединение не будет сохранено, если больше, чем
связи существуют. Это означает, что maxsize не определяет максимальное количество подключений, которые могут быть открыты для конкретного хоста, а только максимальное количество подключений, которые необходимо сохранить в пуле. Однако, если вы укажете [Примечание: доступно как в то с конкретным хостом может быть открыто не более maxsize соединений.]
Учитывая это, вот что произошло в вашем случае:
- Все упомянутые пулы являются пулами КЛИЕНТА. Вы (или) не контролируете какие-либо пулы соединений с серверами
- Это предупреждение о
, то есть количество одновременных подключений к одному и тому же хосту , поэтому вы можете увеличить, чтобы соответствовать количеству рабочих / потоков, которые вы используете, чтобы избавиться от предупреждения. - Обратите внимание, что
уже открывает столько одновременных подключений, сколько вы запрашиваете, независимо от того ,. Если у вас 100 потоков, он откроет 100 подключений. Но со значением по умолчанию только 10 из них будут сохранены в пуле для последующего повторного использования, а 90 будут отброшены после выполнения запроса. - Таким образом, больший
увеличивает производительность одного хоста за счет повторного использования соединений , а не за счет увеличения параллелизма. - Если вы имеете дело с несколькими хостами , вы можете изменить
вместо. По умолчанию уже установлено 10, поэтому, если все ваши запросы относятся к одному и тому же целевому хосту, его увеличение не повлияет на производительность (но увеличит используемые ресурсы, как указано в документации выше).
Если кому-то нужно сделать это с 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 из закрытой проблемы, для справки я добавлю его -> здесь