Ошибка выполнения с постоянным сеансом aiohttp

#python #aiohttp

#python #aiohttp

Вопрос:

Я только начал с aiohttp и столкнулся с проблемой, которую, похоже, не могу разгадать.

Я создаю постоянный сеанс.

session = aiohttp.ClientSession(headers=headers)

 async def fetch(url):
    async with session.get(url) as resp:
        return await resp.json()

async def run():
    task = asyncio.create_task(fetch('https://someurl'))
    await task
  

При вызове run() моя программа вылетает со следующей трассировкой.

 RuntimeError: Timeout context manager should be used inside a task
  

Я не получаю никакой обратной трассировки, и функция выполняется нормально, когда я не использую постоянный сеанс. То есть, run выполняется, как ожидалось, когда я определяю fetch следующим образом.

 async def fetch(url):
    async with aiohttp.ClientSession(headers=headers) as see:
        async with session.get(url) as resp:
            return await resp.json()
  

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

1. def run нет async , поэтому вы не можете использовать await внутри него. Возможно, форматирование post неверно?

2. Да, я пропустил async ключевое слово при публикации вопроса. Я внес изменения в свой исходный пост.

Ответ №1:

Вам нужно будет перейти session = ...ClientSession внутрь fetch , также было бы лучше использовать async with при создании сеанса.

Что-то вроде

 async def fetch(url):
    async with aiohttp.ClientSession(headers=headers) as session:
        async with session.get(url) as resp:
            return await resp.json()

async def run():
    task = asyncio.create_task(fetch('https://someurl'))
    await task
  

Обновленный, более полный пример:

 class Foboar():
    def __init__(self):
        self.session = None

    async def run(self):
        self.session = aiohttp.ClientSession(headers=headers)
        try:
            for url in all_my_urls:
                await self.fetch(url)
        finally:
            await self.session.close()

    async def fetch(self, url):
        async with self.session.get(url) as resp:
            return await resp.json()
  

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

1. Это работает, но в конечном итоге я создаю новый сеанс для каждого выполняемого запроса. Как я могу сохранить сеанс для повторного использования, а не создавать новый сеанс при каждом вызове fetch

2. да, поэтому создайте сеанс в run и передавайте его каждому fetch вызову. Посмотрите на основной пример здесь .

3. Согласно docs.aiohttp.org/en/stable /… диспетчер контекста сеанса не требуется, что я и делаю. Более того, предлагаемый вами подход по-прежнему создает новый сеанс при каждом вызове run . Я хочу создать для session каждого сайта что-то вроде инициализации self.session = aiohttp.ClientSession() при инициализации моего HttpClient.

4. извините, я спешил, обновился более полным примером реализации self.session .

5. Чем это отличается от моего первоначального вопроса? После run вызова, self.session будет привязан к экземпляру aiohttp.ClientSession и в моем коде я привязываюсь session к aiohttp.ClientSession перед вызовом run . Единственный способ заставить мой код работать — это пройти timeout=None , но увидеть другие проблемы.