Ввода-вывода.собрать против ввода-вывода.ждать


asyncio.gather и asyncio.wait похоже, что у меня есть аналогичное использование: у меня есть куча асинхронных вещей, которые я хочу выполнить/подождать (не обязательно ждать, пока один из них закончится до начала следующего). Они используют различный синтаксис, и отличаются в некоторых деталях, но, похоже, очень ООН-подходящие для Python для меня есть 2 функции, которые имеют такую огромную работу. Чего мне не хватает?

3 53

3 ответа:

хотя подобные в общих случаях ("запуск и получение результатов для многих задач"), каждая функция имеет определенную функциональность для других случаев:

asyncio.gather()

возвращает будущий экземпляр, позволяющий группировать задачи высокого уровня:

import asyncio
from pprint import pprint

import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(1, 3))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

group1 = asyncio.gather(*[coro("group 1.{}".format(i)) for i in range(1, 6)])
group2 = asyncio.gather(*[coro("group 2.{}".format(i)) for i in range(1, 4)])
group3 = asyncio.gather(*[coro("group 3.{}".format(i)) for i in range(1, 10)])

all_groups = asyncio.gather(group1, group2, group3)

results = loop.run_until_complete(all_groups)

loop.close()

pprint(results)

все задачи в группе можно отменить, позвонив group2.cancel() или даже all_groups.cancel(). Смотрите также .gather(..., return_exceptions=True),

asyncio.wait()

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

import asyncio
import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(0.5, 5))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

tasks = [coro(i) for i in range(1, 11)]

print("Get first result:")
finished, unfinished = loop.run_until_complete(
    asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED))

for task in finished:
    print(task.result())
print("unfinished:", len(unfinished))

print("Get more results in 2 seconds:")
finished2, unfinished2 = loop.run_until_complete(
    asyncio.wait(unfinished, timeout=2))

for task in finished2:
    print(task.result())
print("unfinished2:", len(unfinished2))

print("Get all other results:")
finished3, unfinished3 = loop.run_until_complete(asyncio.wait(unfinished2))

for task in finished3:
    print(task.result())

loop.close()

asyncio.wait является более низким уровнем, чем asyncio.gather.

как следует из названия,asyncio.gather в основном фокусируется на сборе результатов. он ждет кучу фьючерсов и возвращает их результаты в заданном порядке.

asyncio.wait просто ждет на фьючерсы. и вместо того, чтобы давать вам результаты напрямую, он дает выполненные и отложенные задачи. вы должны манерно собирать ценности.

кроме того, вы можете указать, чтобы дождаться завершения всех фьючерсов или только первого с wait.

Я также заметил, что вы можете предоставить группу сопрограмм в ожидании (), просто указав список:

result=loop.run_until_complete(asyncio.wait([
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ]))

в то время как группировка в gather() выполняется путем простого указания нескольких сопрограмм:

result=loop.run_until_complete(asyncio.gather(
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ))