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

Key Takeaways
errgroupvereinfacht die Verwaltung von parallelen Goroutinen mit Fehlerbehandlung und Kontextabbruch.- Die Verwendung von
WithContextermöglicht die frühzeitige Beendigung aller Goroutinen im Fehlerfall. SetLimitsteuert 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
Groupund 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
WithContextverwenden, 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:
errgrouperfasst 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



