Asyncio.gather vs asyncio.wait


150

asyncio.gathere asyncio.waitsembrano avere usi simili: ho un sacco di cose asincrone che voglio eseguire / attendere (non necessariamente aspettando che uno finisca prima che inizi il successivo). Usano una sintassi diversa e differiscono in alcuni dettagli, ma mi sembra molto poco pitonico avere 2 funzioni che hanno una così grande sovrapposizione di funzionalità. Cosa mi sto perdendo?

Risposte:


178

Sebbene simile nei casi generali ("esegui e ottieni risultati per molte attività"), ogni funzione ha alcune funzionalità specifiche per altri casi:

asyncio.gather()

Restituisce un'istanza Future, consentendo il raggruppamento di attività di alto livello:

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)

Tutte le attività di un gruppo possono essere annullate chiamando group2.cancel()o anche all_groups.cancel(). Vedi anche .gather(..., return_exceptions=True),

asyncio.wait()

Supporta l'attesa di essere arrestata dopo che è stata eseguita la prima attività o dopo un timeout specificato, consentendo una precisione delle operazioni di livello inferiore:

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
"Il singolo modulo asterisco (* args) viene utilizzato per passare un elenco di argomenti di lunghezza variabile senza parole chiave e il modulo doppio asterisco viene utilizzato per passare un elenco di argomenti di lunghezza variabile
parole chiave

41

asyncio.waitè più basso livello di asyncio.gather.

Come suggerisce il nome, asyncio.gathersi concentra principalmente sulla raccolta dei risultati. attende un sacco di futures e restituisce i loro risultati in un determinato ordine.

asyncio.waitaspetta solo il futuro. e invece di darti i risultati direttamente, ti dà compiti fatti e in sospeso. devi raccogliere manualmente i valori.

Inoltre, è possibile specificare di attendere il completamento di tutti i future o il primo con wait.


Tu dici: it waits on a bunch of futures and return their results in a given order. cosa succede se ho 10000000000000 attività e tutte restituiscono dati di grandi dimensioni? tutto il risultato farà esplodere la memoria?
Kingname

@Kingname ..wat
Matt Joiner il

14

Ho anche notato che puoi fornire un gruppo di coroutine in wait () semplicemente specificando l'elenco:

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

Considerando che il raggruppamento in gather () è fatto semplicemente specificando più coroutine:

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

20
Gli elenchi possono essere utilizzati anche con gather(), ad esempio:asyncio.gather(*task_list)
tehfink

1
Anche i generatori possono
farlo

Come puoi usare questo raggruppamento senza bloccare il resto dello script?
thebeancounter il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.