Где я могу поймать исключение KeyboardInterrupt в этой настройке асинхронной
Я работаю над проектом, который использует ccxt
асинхронная библиотека, которая требует, чтобы все ресурсы, используемые определенным классом, были освобождены с явным вызовом класса .close()
сопрограммная. Я хочу выйти из программы с ctrl+c
и жду закрытия сопрограммы в исключении. Однако этого никогда не ожидается.
Приложение состоит из модулей harvesters
, strategies
, traders
, broker
, а также main
(плюс конфиг и тому подобное). Брокер инициирует стратегии, указанные для обмена, и выполняет их. Стратегия инициирует связанный харвестер, который собирает необходимые данные. Он также анализирует данные и порождает трейдера, когда есть выгодная возможность. Основной модуль создает брокера для каждой биржи и запускает его. Я пытался поймать исключение на каждом из этих уровней, но близкая рутина никогда не ожидалась. Я бы предпочел поймать его в главном модуле, чтобы закрыть все экземпляры exchange.
уборочная машина
async def harvest(self):
if not self.routes:
self.routes = await self.get_routes()
for route in self.routes:
self.logger.info("Harvesting route {}".format(route))
await asyncio.sleep(self.exchange.rateLimit / 1000)
yield await self.harvest_route(route)
стратегия
async def execute(self):
async for route_dct in self.harvester.harvest():
self.logger.debug("Route dictionary: {}".format(route_dct))
await self.try_route(route_dct)
Маклер
async def run(self):
for strategy in self.strategies:
self.strategies[strategy] = getattr(
strategies, strategy)(self.share, self.exchange, self.currency)
while True:
try:
await self.execute_strategies()
except KeyboardInterrupt:
await safe_exit(self.exchange)
Главный
async def main():
await load_exchanges()
await load_markets()
brokers = [Broker(
share,
exchanges[id]["api"],
currency,
exchanges[id]["strategies"]
) for id in exchanges]
futures = [broker.run() for broker in brokers]
for future in asyncio.as_completed(futures):
executed = await future
return executed
if __name__ == "__main__":
status = asyncio.run(main())
sys.exit(status)
Я ожидал close()
ожидание сопрограммы, но я все еще получаю сообщение об ошибке из библиотеки, которое я должен явно вызвать. Где я могу поймать исключение, чтобы все экземпляры обмена были закрыты должным образом?
1 ответ
Где-то в вашем коде должна быть точка входа, где начинается цикл обработки событий.
Обычно это одна из функций ниже:
loop.run_until_complete(main())
loop.run_forever()
asyncio.run(main())
когда ctrl+C
происходит KeyboardInterrupt
можно поймать на этой линии. Когда это случилось, чтобы выполнить некоторую завершающую сопрограмму, вы можете снова запустить цикл обработки событий.
Этот маленький пример показывает идею:
import asyncio
async def main():
print('Started, press ctrl+C')
await asyncio.sleep(10)
async def close():
print('Finalazing...')
await asyncio.sleep(1)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
except KeyboardInterrupt:
loop.run_until_complete(close())
finally:
print('Program finished')