Клиентская сессия Python aiohttp запрашивает утечку памяти?

#python #python-asyncio #aiohttp

Вопрос:

Я полагаю, что обнаружил утечку памяти в своем приложении с длительным сроком службы при использовании запросов aiohttp-клиентов. Если каждая сопрограмма, которая делает запрос, ожидается последовательно, то все кажется прекрасным. Однако, похоже, при одновременном запуске происходит утечка объектов диспетчера контекста запроса.

Пожалуйста, рассмотрите следующий пример кода:

 import logging
import tracemalloc
import asyncio
import aiohttp


async def log_allocations_coro():

    while True:
        await asyncio.sleep(120)
        snapshot = tracemalloc.take_snapshot()
        top_stats = snapshot.statistics('lineno')
        str_list = [str(x) for x in top_stats[:5]]
        logging.info("n".join(str_list))


async def do_request():

    try:
        async with session.request("GET", "http://192.168.1.1") as response:
            text = await response.text()
    except:
        logging.exception("Request failed")


async def main():

    tracemalloc.start()
    asyncio.ensure_future(log_allocations_coro())
    
    timeout = aiohttp.ClientTimeout(total=1)
    global session
    session = aiohttp.ClientSession(timeout=timeout)

    while True:

        tasks = [ do_request(), do_request() ]
        await asyncio.gather(*tasks)
        await asyncio.sleep(2)


if __name__ == '__main__':

    logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
 

tracemalloc Сопрограмма регистрирует выделение памяти каждые две минуты. Это показывает, что количество распределений в aiohttp/client.py where request() со _RequestContextManager временем увеличивается, сначала быстро, но затем замедляется до достижения пика, а затем кажется довольно стабильным.
Однако затем было замечено, что если возникает проблема с сетью и запросы начинают отказывать, то счетчик снова увеличивается — и не снижается после устранения проблемы.

Это утечка информации? Если да, то есть ли способ обойти это?

Спасибо за чтение!

Комментарии:

1. Возможно, вам следует опубликовать код с tracemalloc внутри, чтобы предоставить нам более подробную информацию для воспроизведения потенциальной утечки памяти. Просто мысль : ваш код не закрывает клиента. Объект сеанса клиента, так что, может быть, это может быть ключом к разгадке ?

2. Спасибо @Julien, код tracemalloc был опущен для ясности/краткости, но я мог бы включить его, если это может помочь. У вас есть хорошая идея о том, чтобы не закрывать объект ClientSession, но это долговечное приложение, которое никогда не завершается, поэтому нет точки, где его следует закрывать. Однако это может быть потенциальным обходным путем — периодически закрывайте сеанс и начинайте новый.

3. Привет @Julien, я обновил код, чтобы он был полным примером.