Python Asyncio - похоже, не работает в асинхронном режиме

Я написал ниже код, но, похоже, он не дает истинного асинхронного результата.

код:

   async def getOHLC(kc, symbol):
        print("before .... " + symbol)
        ohlc_val = kc.ohlc(symbol)
        print(ohlc_val)
        print("after .... " + symbol)
    
    
    async def trackPrice(kc):
        stocks_array = []
        with open('../config/stocks.txt') as f:
            for line in f:
                stocks_array.append(line.rstrip('\n'))
    
        await asyncio.gather(*[getOHLC(kc, stock) for stock in stocks_array])
    
    if __name__ == "__main__":
        import time
        s = time.perf_counter()
        asyncio.run(trackPrice(connect()))
        elapsed = time.perf_counter() - s
        print(f"{__file__} executed in {elapsed:0.2f} seconds.")

Результат:

 2020-12-13 21:37:21: Establishing connection ....
before .... NSE:TCS
{'NSE:TCS': {'instrument_token': 2953217, 'last_price': 2783.6, 'ohlc': {'open': 2792.7, 'high': 2807.7, 'low': 2764.55, 'close': 2784.3}}}
after .... NSE:TCS
before .... NSE:INFY
{'NSE:INFY': {'instrument_token': 408065, 'last_price': 1163.2, 'ohlc': {'open': 1159.7, 'high': 1171.95, 'low': 1155.25, 'close': 1167.75}}}
after .... NSE:INFY
before .... NSE:WIPRO
{'NSE:WIPRO': {'instrument_token': 969473, 'last_price': 353.5, 'ohlc': {'open': 357.4, 'high': 360, 'low': 352.65, 'close': 355.9}}}
after .... NSE:WIPRO
before .... NSE:ITC
{'NSE:ITC': {'instrument_token': 424961, 'last_price': 216.3, 'ohlc': {'open': 214.45, 'high': 217.95, 'low': 213.35, 'close': 212.7}}}
after .... NSE:ITC
before .... NSE:TINPLATE
{'NSE:TINPLATE': {'instrument_token': 894209, 'last_price': 145.25, 'ohlc': {'open': 146.3, 'high': 150.4, 'low': 143.6, 'close': 145.35}}}
after .... NSE:TINPLATE
before .... NSE:ALLCARGO
{'NSE:ALLCARGO': {'instrument_token': 3456257, 'last_price': 140.9, 'ohlc': {'open': 154, 'high': 155, 'low': 138, 'close': 139.1}}}
after .... NSE:ALLCARGO
before .... NSE:GDL
{'NSE:GDL': {'instrument_token': 3004161, 'last_price': 115.05, 'ohlc': {'open': 117, 'high': 118.4, 'low': 114.7, 'close': 114.85}}}
after .... NSE:GDL
before .... NSE:RELIANCE
{'NSE:RELIANCE': {'instrument_token': 738561, 'last_price': 2005.8, 'ohlc': {'open': 2013, 'high': 2038, 'low': 1974.25, 'close': 2007}}}
after .... NSE:RELIANCE
before .... NSE:TRF
{'NSE:TRF': {'instrument_token': 4604673, 'last_price': 112.5, 'ohlc': {'open': 112.9, 'high': 116.9, 'low': 110, 'close': 106.3}}}
after .... NSE:TRF
before .... NSE:PNCINFRA
{'NSE:PNCINFRA': {'instrument_token': 2402561, 'last_price': 179.5, 'ohlc': {'open': 189.7, 'high': 189.7, 'low': 177.85, 'close': 175.15}}}
after .... NSE:PNCINFRA
before .... NSE:DMART
{'NSE:DMART': {'instrument_token': 5097729, 'last_price': 2685.1, 'ohlc': {'open': 2647, 'high': 2715, 'low': 2632, 'close': 2622.05}}}
after .... NSE:DMART
before .... NSE:HEROMOTOCO
{'NSE:HEROMOTOCO': {'instrument_token': 345089, 'last_price': 3185.3, 'ohlc': {'open': 3200, 'high': 3239.5, 'low': 3169, 'close': 3194.3}}}
after .... NSE:HEROMOTOCO
before .... NSE:MAHLOG
{'NSE:MAHLOG': {'instrument_token': 98561, 'last_price': 406.1, 'ohlc': {'open': 405, 'high': 427.95, 'low': 402.1, 'close': 390.25}}}
after .... NSE:MAHLOG
before .... NSE:IRCON
{'NSE:IRCON': {'instrument_token': 1276417, 'last_price': 90.85, 'ohlc': {'open': 96, 'high': 96, 'low': 90, 'close': 88}}}
after .... NSE:IRCON
before .... NSE:VOLTAS
{'NSE:VOLTAS': {'instrument_token': 951809, 'last_price': 804.9, 'ohlc': {'open': 814, 'high': 820.9, 'low': 800.55, 'close': 814.25}}}
after .... NSE:VOLTAS
/Users/manjulamkumar/Desktop/myRepo/DEV/autoTrade/batch/access_token.py executed in 19.84 seconds.

не могли бы вы помочь мне определить, если я что-то упустил? Получение данных по 15 акциям занимает почти 20 секунд. Хотя я ожидал, что это займет максимум 5 секунд.

Может быть, ваша getOHLC функция должна что-то await?

Tomalak 13.12.2020 17:21

В отличие от многопоточности, вы не можете применить asyncio к существующему коду и ожидать, что он станет параллельным, асинхронный код должен использовать асинхронную функциональность с нуля. Как указывает Томалак, getOHLC ничего не делает await, что является хорошим показателем того, что он «асинхронный» только по названию. Выполнение неожидающей функции не может быть приостановлено, когда функции нужно дождаться результата, и поэтому asyncio.gather() будет выполнять такие функции последовательно. Чтобы решить эту проблему, вам нужно либо переключиться на библиотеку с поддержкой asyncio, либо использовать потоки вместо asyncio.

user4815162342 13.12.2020 17:40

Чтение файла является дорогостоящей операцией. Я думаю, он должен ждать там.

Tarique 14.12.2020 16:01

@user4815162342 user4815162342 Кстати, спасибо за ваши посты на SO, вы отличный учитель асинхронности :)

madzohan 15.12.2020 15:30

@madzohan Приятно слышать, спасибо!

user4815162342 15.12.2020 15:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте открыть и прочитать файл с библиотекой aiofile и удалить второй избыточный цикл for и async-gather, и yes должен переписать все нижние вызовы для асинхронного поведения (await kc.ohlc(symbol) # ... etc)

    # ...
    async with AIOFile('../config/stocks.txt', 'r') as afp:
        async for line in LineReader(afp):
            await getOHLC(kc, line.rstrip('\n'))
    # ...

Насколько я понимаю, '../config/stocks.txt' используется для списка символов конфигурации во время запуска. Основная проблема заключается в непонимании конструкции отверстий в этом коде. Функция getOHLC должна быть асинхронной по своей природе, а не просто обернутой в async def

valentinmk 16.12.2020 15:43
Ответ принят как подходящий

getOHLC метод не имеет предела текучести (await something выражение).

Вот почему у asyncio нет возможности переключаться между сопрограммами.

kc.ohlc(symbol) - это вызов API, и он не кажется асинхронной функцией, и, следовательно, если я попытаюсь дождаться его ошибок.

Manjulam Kumar 17.12.2020 17:28

Если это солнечно - вы не можете получить никакой выгоды от asyncio, извините.

Andrew Svetlov 19.12.2020 16:56

Другие вопросы по теме