Verwaltung paralleler Aufgaben in Go mit `errgroup`
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
errgroup
vereinfacht die Verwaltung von parallelen Goroutinen mit Fehlerbehandlung und Kontextabbruch.- Die Verwendung von
WithContext
ermöglicht die frühzeitige Beendigung aller Goroutinen im Fehlerfall. SetLimit
steuert die Anzahl der aktiven, parallelen Goroutinen, um die Ressourcennutzung zu optimieren.
Das errgroup
-Paket in Go bietet Synchronisation, Fehlerweitergabe und Kontextabbruch für Gruppen von Goroutinen, die an Teilaufgaben einer gemeinsamen Aufgabe arbeiten. Es ist Teil des Moduls golang.org/x/sync
und bietet eine bequeme Möglichkeit, parallele Operationen zu verwalten, die Fehler zurückgeben können.
Überblick über errgroup
Das errgroup
-Paket wurde entwickelt, um die Verwaltung mehrerer Goroutinen zu vereinfachen, die verwandte Aufgaben ausführen. Es erweitert die Funktionalität von sync.WaitGroup
um Fehlerbehandlungs- und Kontextabbruchfunktionen. Das bedeutet, dass die gesamte Gruppe abgebrochen und der Fehler an den Aufrufer zurückgegeben werden kann, wenn eine Goroutine auf einen Fehler stößt.
Hauptkomponenten
Zu den Hauptkomponenten des errgroup
-Pakets gehören:
- Group: Eine Sammlung von Goroutinen, die an Teilaufgaben derselben Gesamtaufgabe arbeiten.
- WithContext: Erstellt eine neue
Group
und einen zugehörigenContext
, der vom bereitgestellten Kontext abgeleitet ist. - Go: Registriert eine Funktion, die in einer neuen Goroutine ausgeführt werden soll.
- Wait: Wartet, bis alle registrierten Funktionen abgeschlossen sind, und gibt den ersten Nicht-Nil-Fehler zurück (falls vorhanden).
Grundlegende Verwendung
Hier ist ein Beispiel für die Verwendung von errgroup
zum gleichzeitigen Abrufen mehrerer URLs:
package main import ( "fmt" "net/http" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group var urls = []string{ "http://www.golang.org/", "http://www.google.com/", "http://www.somestupidname.com/", } for _, url := range urls { url := url // create a new variable to avoid closure issues g.Go(func() error { resp, err := http.Get(url) if err == nil { resp.Body.Close() } return err }) } if err := g.Wait(); err == nil { fmt.Println("Successfully fetched all URLs.") } else { fmt.Printf("Failed to fetch URLs: %v\n", err) } }
In diesem Beispiel wird eine errgroup.Group
erstellt, und für jede URL wird eine neue Goroutine gestartet, um eine HTTP-GET-Anforderung auszuführen. Die Methode g.Go
registriert die Funktion, die gleichzeitig ausgeführt werden soll. Die Methode g.Wait
wartet, bis alle Goroutinen abgeschlossen sind, und gibt den ersten aufgetretenen Fehler zurück, falls vorhanden.
Verwenden von errgroup
mit Kontext
Die Funktion WithContext
ermöglicht den Abbruch des Kontexts, wodurch alle Goroutinen abgebrochen werden können, wenn eine von ihnen auf einen Fehler stößt. Dies ist besonders nützlich, wenn die Aufgaben voneinander abhängig sind oder wenn im Fehlerfall eine vorzeitige Beendigung gewünscht wird.
package main import ( "context" "fmt" "golang.org/x/sync/errgroup" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() g, ctx := errgroup.WithContext(ctx) for i := 0; i < 3; i++ { i := i // avoid closure capture g.Go(func() error { if i == 1 { return fmt.Errorf("error in goroutine %d", i) } select { case <-time.After(2 * time.Second): fmt.Printf("goroutine %d completed\n", i) case <-ctx.Done(): fmt.Printf("goroutine %d canceled\n", i) } return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
In diesem Code wird der Kontext abgebrochen, wenn eine Goroutine einen Fehler zurückgibt, wodurch andere Goroutinen vorzeitig beendet werden, wenn sie den Abbruch des Kontexts berücksichtigen.
Steuern der Parallelität mit SetLimit
Mit der Methode SetLimit
können Sie die maximale Anzahl aktiver Goroutinen zu einem bestimmten Zeitpunkt steuern. Dies ist nützlich, um die Ressourcennutzung zu begrenzen, wenn Sie mit einer großen Anzahl von Aufgaben arbeiten.
package main import ( "fmt" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group g.SetLimit(2) // limit to 2 concurrent goroutines for i := 0; i < 5; i++ { i := i // avoid closure capture g.Go(func() error { fmt.Printf("Starting task %d\n", i) // simulate work return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
Hier stellt SetLimit(2)
sicher, dass nicht mehr als zwei Goroutinen gleichzeitig aktiv sind. Neue Goroutinen warten, bis eine aktive Goroutine abgeschlossen ist, bevor sie gestartet werden.
Häufige Fehler
Beachten Sie bei der Verwendung von errgroup
Folgendes:
-
Variablenaufnahme in Closures: Stellen Sie sicher, dass Schleifenvariablen in Closures korrekt erfasst werden, um unerwartetes Verhalten zu vermeiden. Dies geschieht in der Regel durch Erstellen einer neuen Variablen innerhalb der Schleife.
-
Kontextabbruch: Wenn Sie
WithContext
verwenden, sollten Goroutinen den Abbruch des Kontexts berücksichtigen, indem siectx.Done()
überprüfen, um die Ausführung im Falle eines Abbruchs umgehend zu beenden. -
Fehlerbehandlung:
errgroup
erfasst nur den ersten Nicht-Nil-Fehler. Wenn Sie alle Fehler erfassen müssen, müssen Sie eine zusätzliche Fehleraggregationslogik implementieren.
Durch die Nutzung des errgroup
-Pakets können Go-Entwickler komplexe parallele Workflows effektiver verwalten, mit integrierter Fehlerbehandlung und kontextabhängigem Abbruch.
FAQs
errgroup
propagiert Fehler und unterstützt den Abbruch des Kontexts, während sync.WaitGroup
nur auf den Abschluss von Goroutinen wartet.
Der erste Fehler wird zurückgegeben, und wenn WithContext
verwendet wird, erhalten andere Goroutinen ein Abbruchsignal.
Verwenden Sie SetLimit(n)
, um sicherzustellen, dass nur n
Goroutinen gleichzeitig ausgeführt werden.
Wir sind Leapcell, Ihre erste Wahl für das Hosten von Go-Projekten.
Leapcell ist die Serverlose Plattform der nächsten Generation für Webhosting, asynchrone Aufgaben und Redis:
Mehrsprachige Unterstützung
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung – keine Anfragen, keine Gebühren.
Unschlagbare Kosteneffizienz
- Pay-as-you-go ohne Leerlaufgebühren.
- Beispiel: 25 USD unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Antwortzeit von 60 ms.
Optimierte Entwicklererfahrung
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollautomatische CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für verwertbare Erkenntnisse.
Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur einfachen Bewältigung hoher Parallelität.
- Kein Betriebsaufwand – konzentrieren Sie sich einfach auf den Aufbau.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ