diff --git a/examples.txt b/examples.txt index 8859292..289ee58 100644 --- a/examples.txt +++ b/examples.txt @@ -23,6 +23,7 @@ Goroutines Channels Channel Buffering Channel Synchronization +Waiting For Goroutines To Finish Channel Directions Select Timeouts diff --git a/examples/channel-synchronization/channel-synchronization.go b/examples/channel-synchronization/channel-synchronization.go index 4cc1461..6b18be1 100644 --- a/examples/channel-synchronization/channel-synchronization.go +++ b/examples/channel-synchronization/channel-synchronization.go @@ -1,6 +1,8 @@ // We can use channels to synchronize execution // across goroutines. Here's an example of using a // blocking receive to wait for a goroutine to finish. +// When waiting for multiple goroutines to finish, +// you may prefer to [use a WaitGroup](waiting-for-goroutines-to-finish). package main diff --git a/examples/channel-synchronization/channel-synchronization.hash b/examples/channel-synchronization/channel-synchronization.hash index 8680448..8fba20d 100644 --- a/examples/channel-synchronization/channel-synchronization.hash +++ b/examples/channel-synchronization/channel-synchronization.hash @@ -1,2 +1,2 @@ -fe3e2ea1a67d0f95ce4cb18f3e8aa16d416de0ce -0DfW-1RMqi +df90432a53832c045472981a9da23d1139fb2b5c +f6qTtt1agmN diff --git a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go new file mode 100644 index 0000000..db49ad4 --- /dev/null +++ b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go @@ -0,0 +1,47 @@ +// To wait for multiple goroutines to finish, we can +// use a sync.WaitGroup. + +package main + +import ( + "fmt" + "math/rand" + "sync" + "time" +) + +// This is the function we'll run in every goroutine. +// wg is the WaitGroup it uses to notify that it's done. +// Note that a WaitGroup must be passed to functions by +// pointer. +func worker(id int, wg *sync.WaitGroup) { + fmt.Printf("Worker %d starting\n", id) + + // Sleep for a random duration between 500-700 ms + // to simulate work. See the [random numbers](random-numbers) + // example for more details on *rand*. + msToSleep := time.Duration(500 + rand.Intn(200)) + time.Sleep(msToSleep * time.Millisecond) + fmt.Printf("Worker %d done\n", id) + + // Notify the WaitGroup that we're done. + wg.Done() +} + +func main() { + + // This WaitGroup is used to wait for all the + // goroutines launched here to finish. + var wg sync.WaitGroup + + // Launch several goroutines and increment the WorkGroup + // counter for each. + for i := 1; i <= 5; i++ { + wg.Add(1) + go worker(i, &wg) + } + + // Block until the WorkGroup counter goes back to 0; + // all the workers notified they're done. + wg.Wait() +} diff --git a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash new file mode 100644 index 0000000..00b9360 --- /dev/null +++ b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash @@ -0,0 +1,2 @@ +f068072d11ed9469174c18f5b7a6a7d9d8d3dafb +koKzXfbq8kg diff --git a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh new file mode 100644 index 0000000..f68210c --- /dev/null +++ b/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh @@ -0,0 +1,14 @@ +$ go run waiting-for-goroutines-to-finish.go +Worker 5 starting +Worker 3 starting +Worker 4 starting +Worker 1 starting +Worker 2 starting +Worker 4 done +Worker 1 done +Worker 2 done +Worker 5 done +Worker 3 done + +# The order of workers starting up and finishing +# is likely to be different for each invocation. diff --git a/public/channel-synchronization b/public/channel-synchronization index 7a974b3..9c26e54 100644 --- a/public/channel-synchronization +++ b/public/channel-synchronization @@ -27,7 +27,9 @@
We can use channels to synchronize execution across goroutines. Here’s an example of using a -blocking receive to wait for a goroutine to finish.
+blocking receive to wait for a goroutine to finish. +When waiting for multiple goroutines to finish, +you may prefer to use a WaitGroup.package main
- Next example: Channel Directions. + Next example: Waiting For Goroutines To Finish.
+ To wait for multiple goroutines to finish, we can +use a sync.WaitGroup. + + |
+ + + + | +
+ + | +
+ ![]() package main
+ |
+
+ + | +
+
+ import (
+ "fmt"
+ "math/rand"
+ "sync"
+ "time"
+)
+ |
+
+ This is the function we’ll run in every goroutine. +wg is the WaitGroup it uses to notify that it’s done. +Note that a WaitGroup must be passed to functions by +pointer. + + |
+
+
+ func worker(id int, wg *sync.WaitGroup) {
+ fmt.Printf("Worker %d starting\n", id)
+ |
+
+ Sleep for a random duration between 500-700 ms +to simulate work. See the random numbers +example for more details on rand. + + |
+
+
+ msToSleep := time.Duration(500 + rand.Intn(200))
+ time.Sleep(msToSleep * time.Millisecond)
+ fmt.Printf("Worker %d done\n", id)
+ |
+
+ Notify the WaitGroup that we’re done. + + |
+
+
+ wg.Done()
+}
+ |
+
+ + | +
+
+ func main() {
+ |
+
+ This WaitGroup is used to wait for all the +goroutines launched here to finish. + + |
+
+
+ var wg sync.WaitGroup
+ |
+
+ Launch several goroutines and increment the WorkGroup +counter for each. + + |
+
+
+ for i := 1; i <= 5; i++ {
+ wg.Add(1)
+ go worker(i, &wg)
+ }
+ |
+
+ Block until the WorkGroup counter goes back to 0; +all the workers notified they’re done. + + |
+
+
+ wg.Wait()
+}
+ |
+
+ + | +
+
+ $ go run waiting-for-goroutines-to-finish.go
+Worker 5 starting
+Worker 3 starting
+Worker 4 starting
+Worker 1 starting
+Worker 2 starting
+Worker 4 done
+Worker 1 done
+Worker 2 done
+Worker 5 done
+Worker 3 done
+ |
+
+ The order of workers starting up and finishing +is likely to be different for each invocation. + + |
+ + + + | +
+ Next example: Channel Directions. +
+ + +