#python #python-asyncio
#python #python-asyncio
Вопрос:
Я хочу создать постоянный сеанс, который будет длиться до завершения программы, у меня есть следующий код.
import asyncio
import aiohttp
import atexit
class Session:
def __init__(self):
self._session = aiohttp.ClientSession()
atexit.re&ister(self._close_session)
async def &et(self, url):
response = await self._session.request("GET", url)
return await response.json()
def _close_session(self):
asyncio.run(self._session.close())
async def pullit():
print(await session.&et("https://raw.communitydra&on.or&/latest/&ame/data/characters/aatrox/aatrox.bin.json"))
session = Session()
asyncio.run(pullit()) # THIS THROWS: Timeout context mana&er should be used inside a task
asyncio.&et_event_loop().run_until_complete(pullit()) #THIS RUNS OK
Это выдает мне исключение в self._session.request
строке с Timeout context mana&er should be used inside a task
, я искал другие ответы, но он по-прежнему выдает ту же ошибку.
Вопрос: В чем причина этой ошибки? Если я хочу открыть сеанс, который длится все время существования программы, и мне нужно, чтобы он был определен внутри класса (обязательно), как бы это было?
Дополнительно: в настоящее время я использую atexit
для закрытия сеанса при завершении программы (см. Приведенный выше код), это хороший способ сделать это? если нет, какова лучшая практика
ОБНОВЛЕНИЕ: я нашел решение для этого, оно должно было использовать asyncio.&et_event_loop().run_until_complete(...)
, но не asyncio.run()
такое же, как указано выше? почему один запускается без проблем, а 3.7 asyncio.run()
не запускается?
ОБНОВЛЕНИЕ 2: в итоге я получил следующий код:
#runner.py
import aiohttp
import asyncio
class Runner:
def __init__(self, coro):
self.coro = coro
async def run(self):
session = aiohttp.ClientSession()
client.start_session(session)
await self.coro
client.close_session()
await session.close()
def run(coro):
runner = Runner(coro)
return asyncio.run(runner.run())
#client.py
class Client:
def __init__(self):
self._session = None
async def &et(self, url):
response = await self._session.request("GET", url)
return await response.json()
def start_session(self, session):
self._session = session
def close_session(self):
self._session = None
from .runner import run
from .client import Client
client = Client()
async def pullit():
print(await client.&et("https://raw.communitydra&on.or&/latest/&ame/data/characters/aatrox/aatrox.bin.json"))
run(pullit())
ХОРОШО, это запускается и все такое, но после запуска это выдает меня RuntimeError: Event loop is closed
, который я никогда не замыкал цикл.
Комментарии:
1. Можете ли вы отредактировать вопрос, включив в него минимальный пример, который воспроизводит ошибку? Неясно, как вы создаете экземпляр и используете
Session
класс.2. Это минимальный пример для класса , позвольте мне включить минимальный пример того, как я использую этот класс, удерживайте вторую ПРАВКУ: обновлено
3. Пожалуйста, обратите внимание, что ваш пример по-прежнему недоступен для выполнения, поскольку он не включает весь импорт, URL и т.д. Я попытался дополнить это следующим образом, но я не могу воспроизвести ошибку, о которой вы сообщаете. Приводит ли эта версия к ошибке при ее запуске? Если нет, не могли бы вы, пожалуйста, отредактировать выполняемый пример, чтобы он выдавал сообщение об ошибке?
4. @user4815162342 Извините за это!! Теперь я отредактировал, и это выдает ошибку, как указано! если я запущу,
asyncio.run
это завершится неудачей, в то время как старый&et_event_loop().run_until_complete()
работает…5. Ваша последняя правка в основном аннулирует весь мой ответ, и я все еще не понимаю ваш дизайн, в частности различие между
run
иpullit
. Я оставлю это на этом; возможно, кто-то другой сможет ответить.
Ответ №1:
Вот мое решение вашей проблемы:
import aiohttp
import asyncio
import atexit
class HTTPClient():
def __init__(self):
self._session = aiohttp.ClientSession()
atexit.re&ister(self._shutdown)
print('session created')
async def request(self, *ar&s, **kwar&s):
async with self._session.request(*ar&s, **kwar&s) as response:
return (response.status, await response.text())
def _shutdown(self):
asyncio.run(self._session.close())
print('session closed')
async def main():
http_client = HTTPClient()
status, text = await http_client.request(url='http://example.com', method='GET')
print(status)
asyncio.run(main())
С другой стороны, я думаю, лучшим подходом должна быть некоторая оболочка вокруг следующего кода:
async with aiohttp.ClientSession() as session:
# perform all needed http calls inside
pass