diff --git a/examples.txt b/examples.txt index 8859292..ddace2d 100644 --- a/examples.txt +++ b/examples.txt @@ -32,6 +32,7 @@ Range over Channels Timers Tickers Worker Pools +WaitGroups Rate Limiting Atomic Counters Mutexes diff --git a/examples/channel-synchronization/channel-synchronization.go b/examples/channel-synchronization/channel-synchronization.go index 4cc1461..66873a8 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](waitgroups). package main diff --git a/examples/channel-synchronization/channel-synchronization.hash b/examples/channel-synchronization/channel-synchronization.hash index 8680448..e906123 100644 --- a/examples/channel-synchronization/channel-synchronization.hash +++ b/examples/channel-synchronization/channel-synchronization.hash @@ -1,2 +1,2 @@ -fe3e2ea1a67d0f95ce4cb18f3e8aa16d416de0ce -0DfW-1RMqi +eb022977181884c2ab0f2b69e50311769e67a509 +8lmP8beav0p diff --git a/examples/waitgroups/waitgroups.go b/examples/waitgroups/waitgroups.go new file mode 100644 index 0000000..dc8d0c1 --- /dev/null +++ b/examples/waitgroups/waitgroups.go @@ -0,0 +1,42 @@ +// To wait for multiple goroutines to finish, we can +// use a *wait group*. + +package main + +import ( + "fmt" + "sync" + "time" +) + +// This is the function we'll run in every goroutine. +// 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 to simulate an expensive task. + time.Sleep(time.Second) + fmt.Printf("Worker %d done\n", id) + + // Notify the WaitGroup that this worker is 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 WaitGroup + // counter for each. + for i := 1; i <= 5; i++ { + wg.Add(1) + go worker(i, &wg) + } + + // Block until the WaitGroup counter goes back to 0; + // all the workers notified they're done. + wg.Wait() +} diff --git a/examples/waitgroups/waitgroups.hash b/examples/waitgroups/waitgroups.hash new file mode 100644 index 0000000..71ecfc8 --- /dev/null +++ b/examples/waitgroups/waitgroups.hash @@ -0,0 +1,2 @@ +499c7ee59b2ae06d2d3171768d9cf11762121a87 +gLLmgcR7YkP diff --git a/examples/waitgroups/waitgroups.sh b/examples/waitgroups/waitgroups.sh new file mode 100644 index 0000000..c2a6c11 --- /dev/null +++ b/examples/waitgroups/waitgroups.sh @@ -0,0 +1,14 @@ +$ go run waitgroups.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/examples/worker-pools/worker-pools.go b/examples/worker-pools/worker-pools.go index 1114a22..eabda7a 100644 --- a/examples/worker-pools/worker-pools.go +++ b/examples/worker-pools/worker-pools.go @@ -42,6 +42,9 @@ func main() { close(jobs) // Finally we collect all the results of the work. + // This also ensures that the worker goroutines have + // finished. An alternative way to wait for multiple + // goroutines is to use a [WaitGroup](waitgroups). for a := 1; a <= 5; a++ { <-results } diff --git a/examples/worker-pools/worker-pools.hash b/examples/worker-pools/worker-pools.hash index 013b2de..9f101b7 100644 --- a/examples/worker-pools/worker-pools.hash +++ b/examples/worker-pools/worker-pools.hash @@ -1,2 +1,2 @@ -1f9acf1e50be05cad73e6b085ed3294892c67d42 -RTRcHA05vV +bc69c6602d438413dcb9ceac112299ee253e4575 +yuHsGf712D1 diff --git a/public/channel-synchronization b/public/channel-synchronization index 7a974b3..307251a 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
+ + | +
+
+ $ go run waitgroups.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: Rate Limiting. +
+ + +package main
Finally we collect all the results of the work.
+Finally we collect all the results of the work. +This also ensures that the worker goroutines have +finished. An alternative way to wait for multiple +goroutines is to use a WaitGroup.
- Next example: Rate Limiting. + Next example: WaitGroups.