#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, я обновил код, чтобы он был полным примером.