Asyncio.gather vs asyncio.wait


150

asyncio.gatherі, asyncio.waitсхоже, мають подібне використання: у мене є маса асинхронних речей, які я хочу виконати / чекати (не обов'язково чекати, коли закінчиться перед початком наступного). Вони використовують інший синтаксис і відрізняються деякими деталями, але мені здається дуже непітонічним наявність двох функцій, які мають таке величезне перекриття у функціональності. Що я пропускаю?

Відповіді:


178

Хоча подібні в загальних випадках ("запустіть і отримайте результати для багатьох завдань"), кожна функція має певну функціональність для інших випадків:

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()

5
"Форма одиничної зірочки (* args) використовується для передачі списку аргументів без ключових слів, змінної довжини, а форма подвійної зірочки використовується для передачі списку аргументів ключових слів, змінної довжини"
laycat

41

asyncio.waitє більш низьким рівнем, ніж asyncio.gather.

Як випливає з назви, в asyncio.gatherосновному фокусується на збиранні результатів. він чекає на купу ф'ючерсів і повертає їх результати в заданому порядку.

asyncio.waitпросто чекає на ф'ючерси. і замість того, щоб давати вам результати безпосередньо, він дає виконані та очікувані завдання. ви повинні щорічно збирати цінності.

Більше того, ви можете вказати, щоб зачекати, коли всі ф'ючерси закінчаться або тільки перший з wait.


Ви говорите: it waits on a bunch of futures and return their results in a given order. що робити, якщо у мене є 10000000000000 завдань, і всі вони повертають великі дані? весь результат зробить бум пам'яті?
Kingname

@Kingname ..wat
Метт Столяр

14

Я також зауважив, що ви можете надати групу процедур у режимі очікування (), просто вказавши список:

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

В той час, як групування в збирання () проводиться шляхом простого зазначення декількох процедур

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

20
Списки також можна використовувати gather(), наприклад:asyncio.gather(*task_list)
tehfink

1
Так можуть
Jab

Як ви можете використовувати цей збір, не блокуючи решту сценарію?
thebeancounter
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.