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.