Как запустить задачу Asyncio без ожидания?

Мне нужно периодически вызывать задачу, но (а) время ожидания почти больше, чем период.

В следующем коде Как я могу запустить задачу do_something() без необходимости await для результата?

 import asyncio
 import time
 from random import randint

 period = 1  # Second


 def get_epoch_ms():
     return int(time.time() * 1000.0)


 async def do_something(name):
     print("Start  :", name, get_epoch_ms())
     try:
         # Do something which may takes more than 1 secs.
         slp = randint(1, 5)
         print("Sleep  :", name, get_epoch_ms(), slp)
         await asyncio.sleep(slp)
     except Exception as e:
         print("Error  :", e)

     print("Finish :", name, get_epoch_ms())


 async def main():
     i = 0
     while True:
         i += 1
         # Todo : this line should be change
         await do_something('T' + str(i))
         await asyncio.sleep(period)


 asyncio.get_event_loop().run_until_complete(main())

Время ожидания результата не может быть меньше, чем время, необходимое для его получения. Можете подробнее описать проблему?

Thilo 27.05.2019 03:30

Да, конечно. Я использую вызовы API для получения данных о криптовалюте с нескольких веб-сайтов. Моя цель - вызвать API получения данных с постоянным периодом (среднее значение последних периодов). давайте предположим, что 60 запросов в минуту. некоторые сайты ленятся отвечать. например, предположим, что все ответы будут доставлены через 10 секунд. на самом деле мне все равно, когда будет получен ответ (или даже у него может быть ошибка тайм-аута через 60 секунд). это ожидание ответа API раздражает. Я просто хочу отправлять запросы с одинаковыми периодами.

Ario 27.05.2019 05:10
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
2
15 344
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вместо того, чтобы запускать сопрограмму, вызовите await, чтобы создать объект задачи, который работает в фоновом режиме. На следующей итерации вы можете проверить, выполнена ли задача, и соответственно ожидать/отменить ее. (В противном случае asyncio будет жаловаться на то, что неожиданные задачи удаляются сборщиком мусора.)

Ответ принят как подходящий

Ваша проблема заключается в использовании run_until_complete(main()), который не удовлетворяет вашей цели параллелизма. Итак, если предположить, что ваши задачи сопрограммы (do_something()) ограничены 5, ваш код будет следующим:

import time
from random import randint

period = 1  # Second

def get_epoch_ms():
    return int(time.time() * 1000.0)

async def do_something(name):
    print("Start  :", name, get_epoch_ms())
    try:
        # Do something which may takes more than 1 secs.
        slp = randint(1, 5)
        print("Sleep  :", name, get_epoch_ms(), slp)
        await asyncio.sleep(slp)
    except Exception as e:
        print("Error  :", e)

    print("Finish :", name, get_epoch_ms())

loop = asyncio.get_event_loop()
futures = [loop.create_task(do_something('T' + str(i)))
           for i in range(5)]

loop.run_forever()

for f in futures:
    f.cancel()

Вот рабочий процесс параллелизма в его выводе:

Start  : T0 1558937750705
Sleep  : T0 1558937750705 5
Start  : T1 1558937750705
Sleep  : T1 1558937750705 1
Start  : T2 1558937750705
Sleep  : T2 1558937750705 4
Start  : T3 1558937750705
Sleep  : T3 1558937750705 5
Start  : T4 1558937750705
Sleep  : T4 1558937750705 5
Finish : T1 1558937751707
Finish : T2 1558937754709
Finish : T0 1558937755707
Finish : T3 1558937755708
Finish : T4 1558937755708

Однако, если ваши задачи сопрограммы не ограничены, вы можете это сделать:

...
async def main(loop):
    i = 0
    while True:
        i += 1
        loop.create_task(do_something('T' + str(i)))
        await asyncio.sleep(period)

loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))

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