Где я могу поймать исключение KeyboardInterrupt в этой настройке асинхронной - PullRequest
0 голосов
/ 05 февраля 2019

Я работаю над проектом, использующим асинхронную библиотеку ccxt, которая требует, чтобы все ресурсы, используемые определенным классом, были освобождены с явным вызовом сопрограммы класса .close().Я хочу выйти из программы с ctrl+c и дождаться закрытия сопрограммы в исключении.Однако этого никогда не ожидается.

Приложение состоит из модулей harvesters, strategies, traders, broker и main (плюс config и тому подобное).Брокер инициирует стратегии, указанные для обмена, и выполняет их.Стратегия инициирует связанный харвестер, который собирает необходимые данные.Он также анализирует данные и порождает трейдера, когда есть выгодная возможность.Основной модуль создает брокера для каждой биржи и запускает его.Я пытался поймать исключение на каждом из этих уровней, но близкая рутина никогда не ожидалась.Я бы предпочел перехватить его в главном модуле, чтобы закрыть все экземпляры обмена.

Харвестер

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)

Main

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 Ответ

0 голосов
/ 05 февраля 2019

Где-то в вашем коде должна быть точка входа, где запускается цикл обработки событий.

Обычно это одна из следующих функций:

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')
...