Asyncio.gather vs asyncio.wait


148

asyncio.gatherund asyncio.waitscheinen ähnliche Verwendungszwecke zu haben: Ich habe eine Reihe von asynchronen Dingen, die ich ausführen / warten möchte (nicht unbedingt darauf warten, dass einer fertig ist, bevor der nächste beginnt). Sie verwenden eine andere Syntax und unterscheiden sich in einigen Details, aber es scheint mir sehr unpythonisch, zwei Funktionen zu haben, die eine so große Überlappung in der Funktionalität aufweisen. Was vermisse ich?

Antworten:


177

Obwohl in allgemeinen Fällen ähnlich ("Ausführen und Ergebnisse für viele Aufgaben abrufen"), verfügt jede Funktion über bestimmte Funktionen für andere Fälle:

asyncio.gather()

Gibt eine zukünftige Instanz zurück, die eine Gruppierung von Aufgaben auf hoher Ebene ermöglicht:

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)

Alle Aufgaben in einer Gruppe können per Anruf group2.cancel()oder sogar abgebrochen werden all_groups.cancel(). Siehe auch .gather(..., return_exceptions=True),

asyncio.wait()

Unterstützt das Warten auf das Stoppen nach Abschluss der ersten Aufgabe oder nach einem bestimmten Zeitlimit, wodurch eine geringere Genauigkeit der Operationen ermöglicht wird:

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
"Das einfache Sternchenformular (* args) wird verwendet, um eine Argumentliste ohne Schlüsselwörter mit variabler Länge zu übergeben, und das doppelte Sternchenformular wird verwendet, um eine Argumentliste mit Schlüsselwörtern variabler Länge zu übergeben"
laycat

40

asyncio.waitist niedriger als asyncio.gather.

Wie der Name schon sagt, asyncio.gatherkonzentriert sich das Hauptaugenmerk auf das Sammeln der Ergebnisse. Es wartet auf eine Reihe von Futures und gibt ihre Ergebnisse in einer bestimmten Reihenfolge zurück.

asyncio.waitwartet nur auf die Zukunft. und anstatt Ihnen die Ergebnisse direkt zu geben, werden erledigte und ausstehende Aufgaben angezeigt. Sie müssen die Werte manuell erfassen.

Darüber hinaus können Sie festlegen, dass alle Futures oder nur die erste mit abgeschlossen werden sollen wait.


Sie sagen : it waits on a bunch of futures and return their results in a given order. Was ist, wenn ich 10000000000000 Aufgaben habe und alle große Datenmengen zurückgeben? das ganze Ergebnis wird den Speicherboom machen?
Kingname

@Kingname ..wat
Matt Joiner

12

Mir ist auch aufgefallen, dass Sie eine Gruppe von Coroutinen in wait () bereitstellen können, indem Sie einfach die Liste angeben:

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

Während die Gruppierung in collect () nur durch Angabe mehrerer Coroutinen erfolgt:

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

20
Listen können auch verwendet werden mit gather()zB:asyncio.gather(*task_list)
tehfink

1
So können Generatoren
Jab

Wie können Sie diese Sammlung verwenden, ohne den Rest des Skripts zu blockieren?
Thebeancounter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.