Заставить asyncio собираться дождаться, пока все задачи не будут выполнены - PullRequest
1 голос
/ 10 ноября 2019

У меня есть функции, которые должны запускаться в paraller и собирать данные за секунду, а затем возвращать данные по истечении времени.

Проблема в том, что одна задача (на мой взгляд) завершается до того, какдругой, в результате чего results будет пустым для этого результата. Ниже приведен пример кода:

import asyncio
import time

async def task(id, end_time):
    print('Started task ', id)
    results = []
    while time.time() < end_time:
        results.append(1)
    return results


async def main():
    while True:
        end_time = time.time() + 1
        results = await asyncio.gather(*[task(i,end_time) for i in range(2)])
        print(len(results[0]), len(results[1]))
try:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
except KeyboardInterrupt:
    pass
finally:
    loop.close()

возвращает

Started task  0
Started task  1
5580452 0

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

1 Ответ

1 голос
/ 10 ноября 2019

Вам не нужно gather их по-другому. То, как вы используете asyncio в порядке.

В вашем task сопрограмме удалите while и просто добавьте к results один раз. Вы увидите, что обе задачи вернут свои результаты.

Проблема в том, что когда вы делаете while time.time(), вы блокируете его, так как он не асинхронный. Таким образом, он запускает цикл while до тех пор, пока не будет выполнено условие end_time.

Затем запускается второе, поскольку coro task никогда не позволяло выполнять что-либо еще в это время. Поскольку оба использовали один и тот же end_time, второе coro никогда не добавится.

Если вы хотите запустить цикл while асинхронно, вам нужно создать для него дополнительную асинхронную логику и await в нейваша task функция.

РЕДАКТИРОВАТЬ: Например, если вы просто хотите вернуть его в цикл обработки событий и разрешить выполнение чего-то еще, просто поместите await asyncio.sleep(0.1) в свой цикл while.

Пример:

async def task(id, end_time):
    print('Started task ', id)
    results = []
    while time.time() < end_time:
        results.append(1)
        await asyncio.sleep(000000000.1)
    return results

Возможности для улучшения:
- asyncio.run(main() заботится о создании цикла событий
- добавление в список является дорогой операцией, попробуйте += 1 в цикле, поэтомуваш results будет 0 в начале, затем выведите результаты, а не их len

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...