Asyncio.gather vs asyncio.wait


148

asyncio.gathere asyncio.waitparece ter usos semelhantes: Eu tenho várias coisas assíncronas que quero executar / esperar (não necessariamente esperando uma terminar antes que a próxima comece). Eles usam uma sintaxe diferente e diferem em alguns detalhes, mas me parece muito pouco pitônico ter duas funções com uma enorme sobreposição de funcionalidades. o que estou perdendo?

Respostas:


177

Embora seja semelhante em casos gerais ("execute e obtenha resultados para muitas tarefas"), cada função possui alguma funcionalidade específica para outros casos:

asyncio.gather()

Retorna uma instância Future, permitindo um agrupamento de alto nível de tarefas:

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)

Todas as tarefas em um grupo podem ser canceladas por chamada group2.cancel()ou até mesmo all_groups.cancel(). Ver também .gather(..., return_exceptions=True),

asyncio.wait()

Suporta a espera para ser interrompida após a conclusão da primeira tarefa ou após um tempo limite especificado, permitindo menor precisão nas operações:

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

4
"O formulário único asterisco (* args) é usado para passar uma lista de argumentos de comprimento variável e não com palavras-chave, e o formulário duplo asterisco é usado para passar uma lista de argumentos com comprimento variável e com
palavras

40

asyncio.waité um nível mais baixo que asyncio.gather.

Como o nome sugere, asyncio.gatherconcentra-se principalmente na coleta dos resultados. aguarda um monte de futuros e retorna seus resultados em uma determinada ordem.

asyncio.waitapenas espera no futuro. e, em vez de fornecer os resultados diretamente, fornece tarefas concluídas e pendentes. você precisa coletar manualmente os valores.

Além disso, você pode especificar aguardar a conclusão de todos os futuros ou apenas o primeiro wait.


Você diz: it waits on a bunch of futures and return their results in a given order. e se eu tiver 10000000000000 tarefas e todas elas retornarem dados grandes? todo o resultado fará o boom da memória?
Kingname 13/12/19

@Kingname ..wat
Matt Joiner

12

Percebi também que você pode fornecer um grupo de corotinas em wait () simplesmente especificando a lista:

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

Enquanto o agrupamento em gather () é feito apenas especificando várias corotinas:

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

20
As listas também podem ser usadas com gather(), por exemplo:asyncio.gather(*task_list)
tehfink

1
Geradores do mesmo modo
Jab

Como você pode usar essa reunião sem bloquear o restante do script?
thebeancounter 18/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.