]> Cypherpunks repositories - gostls13.git/commitdiff
sync: tidy WaitGroup documentation, add WaitGroup.Go example
authorAustin Clements <austin@google.com>
Fri, 4 Apr 2025 16:18:58 +0000 (12:18 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 25 Apr 2025 22:40:11 +0000 (15:40 -0700)
This reframes the WaitGroup documentation with Go at its center and
Add/Done as more "advanced" features.

Updates #63796

Change-Id: I8101972626fdb00c6f7fb185b685227823d10db1
Reviewed-on: https://go-review.googlesource.com/c/go/+/662975
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Austin Clements <austin@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
src/sync/example_test.go
src/sync/waitgroup.go

index ed240e57ae0eb5d9eee88818942bdc9a7f5dd0d2..a019beebc5d26c470995fa7636f3c5aa51f36eac 100644 (file)
@@ -19,6 +19,26 @@ var http httpPkg
 // This example fetches several URLs concurrently,
 // using a WaitGroup to block until all the fetches are complete.
 func ExampleWaitGroup() {
+       var wg sync.WaitGroup
+       var urls = []string{
+               "http://www.golang.org/",
+               "http://www.google.com/",
+               "http://www.example.com/",
+       }
+       for _, url := range urls {
+               // Launch a goroutine to fetch the URL.
+               wg.Go(func() {
+                       // Fetch the URL.
+                       http.Get(url)
+               })
+       }
+       // Wait for all HTTP fetches to complete.
+       wg.Wait()
+}
+
+// This example is equivalent to the main example, but uses Add/Done
+// instead of Go.
+func ExampleWaitGroup_addAndDone() {
        var wg sync.WaitGroup
        var urls = []string{
                "http://www.golang.org/",
index 8511f948ef2c3f9acd220ddf4431b284be733286..811857bb231cc2b1b86507d5d551be428a61830e 100644 (file)
@@ -11,40 +11,39 @@ import (
 )
 
 // A WaitGroup is a counting semaphore typically used to wait
-// for a group of goroutines to finish.
+// for a group of goroutines or tasks to finish.
 //
-// The main goroutine calls [WaitGroup.Add] to set (or increase) the number of
-// goroutines to wait for. Then each of the goroutines
-// runs and calls [WaitGroup.Done] when finished. At the same time,
-// [WaitGroup.Wait] can be used to block until all goroutines have finished.
-//
-// This is a typical pattern of WaitGroup usage to
-// synchronize 3 goroutines, each calling the function f:
+// Typically, a main goroutine will start tasks, each in a new
+// goroutine, by calling [WaitGroup.Go] and then wait for all tasks to
+// complete by calling [WaitGroup.Wait]. For example:
 //
 //     var wg sync.WaitGroup
-//     for range 3 {
-//        wg.Add(1)
-//        go func() {
-//            defer wg.Done()
-//            f()
-//        }()
-//     }
+//     wg.Go(task1)
+//     wg.Go(task2)
 //     wg.Wait()
 //
-// For convenience, the [WaitGroup.Go] method simplifies this pattern to:
+// A WaitGroup may also be used for tracking tasks without using Go to
+// start new goroutines by using [WaitGroup.Add] and [WaitGroup.Done].
+//
+// The previous example can be rewritten using explicitly created
+// goroutines along with Add and Done:
 //
 //     var wg sync.WaitGroup
-//     for range 3 {
-//        wg.Go(f)
-//     }
+//     wg.Add(1)
+//     go func() {
+//             defer wg.Done()
+//             task1()
+//     }()
+//     wg.Add(1)
+//     go func() {
+//             defer wg.Done()
+//             task2()
+//     }()
 //     wg.Wait()
 //
-// A WaitGroup must not be copied after first use.
-//
-// In the terminology of [the Go memory model], a call to [WaitGroup.Done]
-// “synchronizes before” the return of any Wait call that it unblocks.
+// This pattern is common in code that predates [WaitGroup.Go].
 //
-// [the Go memory model]: https://go.dev/ref/mem
+// A WaitGroup must not be copied after first use.
 type WaitGroup struct {
        noCopy noCopy
 
@@ -52,10 +51,12 @@ type WaitGroup struct {
        sema  uint32
 }
 
-// Add adds delta, which may be negative, to the [WaitGroup] counter.
+// Add adds delta, which may be negative, to the [WaitGroup] task counter.
 // If the counter becomes zero, all goroutines blocked on [WaitGroup.Wait] are released.
 // If the counter goes negative, Add panics.
 //
+// Callers should prefer [WaitGroup.Go].
+//
 // Note that calls with a positive delta that occur when the counter is zero
 // must happen before a Wait. Calls with a negative delta, or calls with a
 // positive delta that start when the counter is greater than zero, may happen
@@ -107,12 +108,20 @@ func (wg *WaitGroup) Add(delta int) {
        }
 }
 
-// Done decrements the [WaitGroup] counter by one.
+// Done decrements the [WaitGroup] task counter by one.
+// It is equivalent to Add(-1).
+//
+// Callers should prefer [WaitGroup.Go].
+//
+// In the terminology of [the Go memory model], a call to Done
+// "synchronizes before" the return of any Wait call that it unblocks.
+//
+// [the Go memory model]: https://go.dev/ref/mem
 func (wg *WaitGroup) Done() {
        wg.Add(-1)
 }
 
-// Wait blocks until the [WaitGroup] counter is zero.
+// Wait blocks until the [WaitGroup] task counter is zero.
 func (wg *WaitGroup) Wait() {
        if race.Enabled {
                race.Disable()
@@ -151,7 +160,7 @@ func (wg *WaitGroup) Wait() {
        }
 }
 
-// Go calls f in a new goroutine and adds that task to the WaitGroup.
+// Go calls f in a new goroutine and adds that task to the [WaitGroup].
 // When f returns, the task is removed from the WaitGroup.
 //
 // If the WaitGroup is empty, Go must happen before a [WaitGroup.Wait].
@@ -161,8 +170,10 @@ func (wg *WaitGroup) Wait() {
 // If a WaitGroup is reused to wait for several independent sets of tasks,
 // new Go calls must happen after all previous Wait calls have returned.
 //
-// In the terminology of [the Go memory model](https://go.dev/ref/mem),
-// the return from f "synchronizes before" the return of any Wait call that it unblocks.
+// In the terminology of [the Go memory model], the return from f
+// "synchronizes before" the return of any Wait call that it unblocks.
+//
+// [the Go memory model]: https://go.dev/ref/mem
 func (wg *WaitGroup) Go(f func()) {
        wg.Add(1)
        go func() {