From 6ab81bdf71ec1cbfb178fecde2f1d32beec35eeb Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 29 May 2019 06:01:58 -0700 Subject: [PATCH 01/10] Add "Waiting For Goroutines To Finish" example. Also link to it from the Channel Synchronization example --- examples.txt | 1 + .../channel-synchronization.go | 2 + .../channel-synchronization.hash | 4 +- .../waiting-for-goroutines-to-finish.go | 47 ++++ .../waiting-for-goroutines-to-finish.hash | 2 + .../waiting-for-goroutines-to-finish.sh | 14 ++ public/channel-synchronization | 8 +- public/index.html | 2 + public/waiting-for-goroutines-to-finish | 223 ++++++++++++++++++ 9 files changed, 298 insertions(+), 5 deletions(-) create mode 100644 examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go create mode 100644 examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash create mode 100644 examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh create mode 100644 public/waiting-for-goroutines-to-finish 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.

@@ -41,7 +43,7 @@ blocking receive to wait for a goroutine to finish.

- +
package main
 
@@ -169,7 +171,7 @@ started.

- Next example: Channel Directions. + Next example: Waiting For Goroutines To Finish.

  • Channel Synchronization
  • +
  • Waiting For Goroutines To Finish
  • +
  • Channel Directions
  • Select
  • diff --git a/public/waiting-for-goroutines-to-finish b/public/waiting-for-goroutines-to-finish new file mode 100644 index 0000000..4f20729 --- /dev/null +++ b/public/waiting-for-goroutines-to-finish @@ -0,0 +1,223 @@ + + + + + Go by Example: Waiting For Goroutines To Finish + + + + +
    +

    Go by 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. +

    + + +
    + + From 74ca2a7b0f812690b0e5e5198ae03667da9219a8 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:28:29 -0700 Subject: [PATCH 02/10] Addressing review comments * Renamed the example * Reworded comments * Moved it to after worker pools * Sleep for a second instead of random * Mention the new sample in worker pools --- examples.txt | 2 +- .../waitgroup.go} | 11 +--- examples/waitgroup/waitgroup.hash | 2 + .../waitgroup.sh} | 2 +- .../waiting-for-goroutines-to-finish.hash | 2 - examples/worker-pools/worker-pools.go | 55 ++++++++++--------- examples/worker-pools/worker-pools.hash | 4 +- public/channel-synchronization | 2 +- public/index.html | 4 +- public/worker-pools | 10 +++- 10 files changed, 48 insertions(+), 46 deletions(-) rename examples/{waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go => waitgroup/waitgroup.go} (70%) create mode 100644 examples/waitgroup/waitgroup.hash rename examples/{waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh => waitgroup/waitgroup.sh} (85%) delete mode 100644 examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash diff --git a/examples.txt b/examples.txt index 289ee58..6153867 100644 --- a/examples.txt +++ b/examples.txt @@ -23,7 +23,6 @@ Goroutines Channels Channel Buffering Channel Synchronization -Waiting For Goroutines To Finish Channel Directions Select Timeouts @@ -33,6 +32,7 @@ Range over Channels Timers Tickers Worker Pools +WaitGroup Rate Limiting Atomic Counters Mutexes diff --git a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go b/examples/waitgroup/waitgroup.go similarity index 70% rename from examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go rename to examples/waitgroup/waitgroup.go index db49ad4..65c4212 100644 --- a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.go +++ b/examples/waitgroup/waitgroup.go @@ -1,27 +1,22 @@ // To wait for multiple goroutines to finish, we can -// use a sync.WaitGroup. +// use a *wait group*. 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) + // Sleep to simulate an expensive task. + time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) // Notify the WaitGroup that we're done. diff --git a/examples/waitgroup/waitgroup.hash b/examples/waitgroup/waitgroup.hash new file mode 100644 index 0000000..1df8a2f --- /dev/null +++ b/examples/waitgroup/waitgroup.hash @@ -0,0 +1,2 @@ +ffc6520e73ebfa2b8c470e3ef00fee55388234e0 +8cD2V9CgI0J diff --git a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh b/examples/waitgroup/waitgroup.sh similarity index 85% rename from examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh rename to examples/waitgroup/waitgroup.sh index f68210c..13293bc 100644 --- a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.sh +++ b/examples/waitgroup/waitgroup.sh @@ -1,4 +1,4 @@ -$ go run waiting-for-goroutines-to-finish.go +$ go run waitgroup.go Worker 5 starting Worker 3 starting Worker 4 starting 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 deleted file mode 100644 index 00b9360..0000000 --- a/examples/waiting-for-goroutines-to-finish/waiting-for-goroutines-to-finish.hash +++ /dev/null @@ -1,2 +0,0 @@ -f068072d11ed9469174c18f5b7a6a7d9d8d3dafb -koKzXfbq8kg diff --git a/examples/worker-pools/worker-pools.go b/examples/worker-pools/worker-pools.go index 1114a22..443957e 100644 --- a/examples/worker-pools/worker-pools.go +++ b/examples/worker-pools/worker-pools.go @@ -12,37 +12,40 @@ import "time" // results on `results`. We'll sleep a second per job to // simulate an expensive task. func worker(id int, jobs <-chan int, results chan<- int) { - for j := range jobs { - fmt.Println("worker", id, "started job", j) - time.Sleep(time.Second) - fmt.Println("worker", id, "finished job", j) - results <- j * 2 - } + for j := range jobs { + fmt.Println("worker", id, "started job", j) + time.Sleep(time.Second) + fmt.Println("worker", id, "finished job", j) + results <- j * 2 + } } func main() { - // In order to use our pool of workers we need to send - // them work and collect their results. We make 2 - // channels for this. - jobs := make(chan int, 100) - results := make(chan int, 100) + // In order to use our pool of workers we need to send + // them work and collect their results. We make 2 + // channels for this. + jobs := make(chan int, 100) + results := make(chan int, 100) - // This starts up 3 workers, initially blocked - // because there are no jobs yet. - for w := 1; w <= 3; w++ { - go worker(w, jobs, results) - } + // This starts up 3 workers, initially blocked + // because there are no jobs yet. + for w := 1; w <= 3; w++ { + go worker(w, jobs, results) + } - // Here we send 5 `jobs` and then `close` that - // channel to indicate that's all the work we have. - for j := 1; j <= 5; j++ { - jobs <- j - } - close(jobs) + // Here we send 5 `jobs` and then `close` that + // channel to indicate that's all the work we have. + for j := 1; j <= 5; j++ { + jobs <- j + } + close(jobs) - // Finally we collect all the results of the work. - for a := 1; a <= 5; a++ { - <-results - } + // 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](waitgroup). + 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..ee8c3c7 100644 --- a/examples/worker-pools/worker-pools.hash +++ b/examples/worker-pools/worker-pools.hash @@ -1,2 +1,2 @@ -1f9acf1e50be05cad73e6b085ed3294892c67d42 -RTRcHA05vV +bfd2824b3840ff67fa9a0218c7be66647b4bf3d9 +IQestAFcxLh diff --git a/public/channel-synchronization b/public/channel-synchronization index 9c26e54..e79fe04 100644 --- a/public/channel-synchronization +++ b/public/channel-synchronization @@ -171,7 +171,7 @@ started.

    - Next example: Waiting For Goroutines To Finish. + Next example: Channel Directions.

  • Channel Synchronization
  • -
  • Waiting For Goroutines To Finish
  • -
  • Channel Directions
  • Select
  • @@ -105,6 +103,8 @@
  • Worker Pools
  • +
  • WaitGroup
  • +
  • Rate Limiting
  • Atomic Counters
  • diff --git a/public/worker-pools b/public/worker-pools index baeb60a..8ff2427 100644 --- a/public/worker-pools +++ b/public/worker-pools @@ -40,7 +40,7 @@ a worker pool using goroutines and channels.

    - +
    package main
     
    @@ -147,7 +147,11 @@ channel to indicate that’s all the work we have.

    -

    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 that’s useful in many scenarios is +to use a WaitGroup.

    @@ -207,7 +211,7 @@ there are 3 workers operating concurrently.

    - Next example: Rate Limiting. + Next example: WaitGroup.

    +

    Go by Example: WaitGroup

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    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 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 waitgroup.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. +

    + + +
    + + From 3010af04fc07dcfd1fe1637b3ccba4cdefb89d18 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:40:18 -0700 Subject: [PATCH 04/10] Rerun tools/build to reformat --- examples/worker-pools/worker-pools.go | 58 ++++++++++++------------- examples/worker-pools/worker-pools.hash | 4 +- public/worker-pools | 5 +-- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/examples/worker-pools/worker-pools.go b/examples/worker-pools/worker-pools.go index 443957e..32ce2f7 100644 --- a/examples/worker-pools/worker-pools.go +++ b/examples/worker-pools/worker-pools.go @@ -12,40 +12,40 @@ import "time" // results on `results`. We'll sleep a second per job to // simulate an expensive task. func worker(id int, jobs <-chan int, results chan<- int) { - for j := range jobs { - fmt.Println("worker", id, "started job", j) - time.Sleep(time.Second) - fmt.Println("worker", id, "finished job", j) - results <- j * 2 - } + for j := range jobs { + fmt.Println("worker", id, "started job", j) + time.Sleep(time.Second) + fmt.Println("worker", id, "finished job", j) + results <- j * 2 + } } func main() { - // In order to use our pool of workers we need to send - // them work and collect their results. We make 2 - // channels for this. - jobs := make(chan int, 100) - results := make(chan int, 100) + // In order to use our pool of workers we need to send + // them work and collect their results. We make 2 + // channels for this. + jobs := make(chan int, 100) + results := make(chan int, 100) - // This starts up 3 workers, initially blocked - // because there are no jobs yet. - for w := 1; w <= 3; w++ { - go worker(w, jobs, results) - } + // This starts up 3 workers, initially blocked + // because there are no jobs yet. + for w := 1; w <= 3; w++ { + go worker(w, jobs, results) + } - // Here we send 5 `jobs` and then `close` that - // channel to indicate that's all the work we have. - for j := 1; j <= 5; j++ { - jobs <- j - } - close(jobs) + // Here we send 5 `jobs` and then `close` that + // channel to indicate that's all the work we have. + for j := 1; j <= 5; j++ { + jobs <- j + } + 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](waitgroup). - for a := 1; a <= 5; a++ { - <-results - } + // 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](waitgroup). + for a := 1; a <= 5; a++ { + <-results + } } diff --git a/examples/worker-pools/worker-pools.hash b/examples/worker-pools/worker-pools.hash index ee8c3c7..4a9a3a2 100644 --- a/examples/worker-pools/worker-pools.hash +++ b/examples/worker-pools/worker-pools.hash @@ -1,2 +1,2 @@ -bfd2824b3840ff67fa9a0218c7be66647b4bf3d9 -IQestAFcxLh +3f7712d470dcbfc0cdddc939bb80814baaff8bb0 +Q5r-XtrWWL- diff --git a/public/worker-pools b/public/worker-pools index 8ff2427..90f35eb 100644 --- a/public/worker-pools +++ b/public/worker-pools @@ -40,7 +40,7 @@ a worker pool using goroutines and channels.

    - +
    package main
     
    @@ -150,8 +150,7 @@ channel to indicate that’s all the work we have.

    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 that’s useful in many scenarios is -to use a WaitGroup.

    +goroutines is to use a WaitGroup.

    From 43ff608b7e990e0eeaa76a7a57b3a46d92fde04c Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:41:16 -0700 Subject: [PATCH 05/10] Remove old location of example in public/ --- public/waiting-for-goroutines-to-finish | 223 ------------------------ 1 file changed, 223 deletions(-) delete mode 100644 public/waiting-for-goroutines-to-finish diff --git a/public/waiting-for-goroutines-to-finish b/public/waiting-for-goroutines-to-finish deleted file mode 100644 index 4f20729..0000000 --- a/public/waiting-for-goroutines-to-finish +++ /dev/null @@ -1,223 +0,0 @@ - - - - - Go by Example: Waiting For Goroutines To Finish - - - - -
    -

    Go by 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. -

    - - -
    - - From 705f713db24fff7065556cb3e2724578dbc70e60 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:53:54 -0700 Subject: [PATCH 06/10] Update examples/channel-synchronization/channel-synchronization.go Co-Authored-By: Mark McGranaghan --- examples/channel-synchronization/channel-synchronization.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/channel-synchronization/channel-synchronization.go b/examples/channel-synchronization/channel-synchronization.go index 6b18be1..a9638ee 100644 --- a/examples/channel-synchronization/channel-synchronization.go +++ b/examples/channel-synchronization/channel-synchronization.go @@ -2,7 +2,7 @@ // 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). +// you may prefer to use a [WaitGroup](waiting-for-goroutines-to-finish). package main From 2967315795d140752523d53cc2ab3623149e8aa2 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:54:10 -0700 Subject: [PATCH 07/10] Update examples/waitgroup/waitgroup.go Co-Authored-By: Mark McGranaghan --- examples/waitgroup/waitgroup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/waitgroup/waitgroup.go b/examples/waitgroup/waitgroup.go index 65c4212..a21a499 100644 --- a/examples/waitgroup/waitgroup.go +++ b/examples/waitgroup/waitgroup.go @@ -29,7 +29,7 @@ func main() { // goroutines launched here to finish. var wg sync.WaitGroup - // Launch several goroutines and increment the WorkGroup + // Launch several goroutines and increment the WaitGroup // counter for each. for i := 1; i <= 5; i++ { wg.Add(1) From c7dd69349b4bb0966c7744c15419be3c703a940c Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 05:54:32 -0700 Subject: [PATCH 08/10] Update examples/waitgroup/waitgroup.go Co-Authored-By: Mark McGranaghan --- examples/waitgroup/waitgroup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/waitgroup/waitgroup.go b/examples/waitgroup/waitgroup.go index a21a499..a1ad603 100644 --- a/examples/waitgroup/waitgroup.go +++ b/examples/waitgroup/waitgroup.go @@ -19,7 +19,7 @@ func worker(id int, wg *sync.WaitGroup) { time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) - // Notify the WaitGroup that we're done. + // Notify the WaitGroup that this worker is done. wg.Done() } From 074571d9523fc3b4316183c1f51c540d0019b3de Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 06:07:12 -0700 Subject: [PATCH 09/10] Update examples/waitgroup/waitgroup.go Co-Authored-By: Mark McGranaghan --- examples/waitgroup/waitgroup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/waitgroup/waitgroup.go b/examples/waitgroup/waitgroup.go index a1ad603..dc8d0c1 100644 --- a/examples/waitgroup/waitgroup.go +++ b/examples/waitgroup/waitgroup.go @@ -36,7 +36,7 @@ func main() { go worker(i, &wg) } - // Block until the WorkGroup counter goes back to 0; + // Block until the WaitGroup counter goes back to 0; // all the workers notified they're done. wg.Wait() } From ec0b192e485c8ccefa34c977a95a81553116a864 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 30 May 2019 06:12:09 -0700 Subject: [PATCH 10/10] Rename waitgroup-->waitgroups --- examples.txt | 2 +- .../channel-synchronization.go | 2 +- .../channel-synchronization.hash | 4 ++-- examples/waitgroup/waitgroup.hash | 2 -- .../waitgroup.go => waitgroups/waitgroups.go} | 0 examples/waitgroups/waitgroups.hash | 2 ++ .../waitgroup.sh => waitgroups/waitgroups.sh} | 2 +- examples/worker-pools/worker-pools.go | 2 +- examples/worker-pools/worker-pools.hash | 4 ++-- public/channel-synchronization | 4 ++-- public/index.html | 2 +- public/{waitgroup => waitgroups} | 18 +++++++++--------- public/worker-pools | 6 +++--- 13 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 examples/waitgroup/waitgroup.hash rename examples/{waitgroup/waitgroup.go => waitgroups/waitgroups.go} (100%) create mode 100644 examples/waitgroups/waitgroups.hash rename examples/{waitgroup/waitgroup.sh => waitgroups/waitgroups.sh} (91%) rename public/{waitgroup => waitgroups} (92%) diff --git a/examples.txt b/examples.txt index 6153867..ddace2d 100644 --- a/examples.txt +++ b/examples.txt @@ -32,7 +32,7 @@ Range over Channels Timers Tickers Worker Pools -WaitGroup +WaitGroups Rate Limiting Atomic Counters Mutexes diff --git a/examples/channel-synchronization/channel-synchronization.go b/examples/channel-synchronization/channel-synchronization.go index a9638ee..66873a8 100644 --- a/examples/channel-synchronization/channel-synchronization.go +++ b/examples/channel-synchronization/channel-synchronization.go @@ -2,7 +2,7 @@ // 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). +// 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 8fba20d..e906123 100644 --- a/examples/channel-synchronization/channel-synchronization.hash +++ b/examples/channel-synchronization/channel-synchronization.hash @@ -1,2 +1,2 @@ -df90432a53832c045472981a9da23d1139fb2b5c -f6qTtt1agmN +eb022977181884c2ab0f2b69e50311769e67a509 +8lmP8beav0p diff --git a/examples/waitgroup/waitgroup.hash b/examples/waitgroup/waitgroup.hash deleted file mode 100644 index 1df8a2f..0000000 --- a/examples/waitgroup/waitgroup.hash +++ /dev/null @@ -1,2 +0,0 @@ -ffc6520e73ebfa2b8c470e3ef00fee55388234e0 -8cD2V9CgI0J diff --git a/examples/waitgroup/waitgroup.go b/examples/waitgroups/waitgroups.go similarity index 100% rename from examples/waitgroup/waitgroup.go rename to examples/waitgroups/waitgroups.go 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/waitgroup/waitgroup.sh b/examples/waitgroups/waitgroups.sh similarity index 91% rename from examples/waitgroup/waitgroup.sh rename to examples/waitgroups/waitgroups.sh index 13293bc..c2a6c11 100644 --- a/examples/waitgroup/waitgroup.sh +++ b/examples/waitgroups/waitgroups.sh @@ -1,4 +1,4 @@ -$ go run waitgroup.go +$ go run waitgroups.go Worker 5 starting Worker 3 starting Worker 4 starting diff --git a/examples/worker-pools/worker-pools.go b/examples/worker-pools/worker-pools.go index 32ce2f7..eabda7a 100644 --- a/examples/worker-pools/worker-pools.go +++ b/examples/worker-pools/worker-pools.go @@ -44,7 +44,7 @@ func main() { // 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](waitgroup). + // 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 4a9a3a2..9f101b7 100644 --- a/examples/worker-pools/worker-pools.hash +++ b/examples/worker-pools/worker-pools.hash @@ -1,2 +1,2 @@ -3f7712d470dcbfc0cdddc939bb80814baaff8bb0 -Q5r-XtrWWL- +bc69c6602d438413dcb9ceac112299ee253e4575 +yuHsGf712D1 diff --git a/public/channel-synchronization b/public/channel-synchronization index e79fe04..307251a 100644 --- a/public/channel-synchronization +++ b/public/channel-synchronization @@ -29,7 +29,7 @@ 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.

    +you may prefer to use a WaitGroup.

    @@ -43,7 +43,7 @@ you may prefer to use a WaitGroup - +
    package main
     
    diff --git a/public/index.html b/public/index.html index d4dd0a2..347a8a3 100644 --- a/public/index.html +++ b/public/index.html @@ -103,7 +103,7 @@
  • Worker Pools
  • -
  • WaitGroup
  • +
  • WaitGroups
  • Rate Limiting
  • diff --git a/public/waitgroup b/public/waitgroups similarity index 92% rename from public/waitgroup rename to public/waitgroups index bdd3b66..7648b36 100644 --- a/public/waitgroup +++ b/public/waitgroups @@ -2,7 +2,7 @@ - Go by Example: WaitGroup + Go by Example: WaitGroups -
    -

    Go by Example: WaitGroup

    +
    +

    Go by Example: WaitGroups

    @@ -40,7 +40,7 @@ use a wait group.

    @@ -152,7 +152,7 @@ counter for each.

    @@ -175,7 +175,7 @@ all the workers notified they’re done.

    - +
    package main
     
    @@ -95,7 +95,7 @@ pointer.

    -

    Notify the WaitGroup that we’re done.

    +

    Notify the WaitGroup that this worker is done.

    @@ -135,7 +135,7 @@ goroutines launched here to finish.

    -

    Launch several goroutines and increment the WorkGroup +

    Launch several goroutines and increment the WaitGroup counter for each.

    -

    Block until the WorkGroup counter goes back to 0; +

    Block until the WaitGroup counter goes back to 0; all the workers notified they’re done.

    -
    $ go run waitgroup.go
    +            
    $ go run waitgroups.go
     Worker 5 starting
     Worker 3 starting
     Worker 4 starting
    @@ -211,7 +211,7 @@ is likely to be different for each invocation.

    diff --git a/public/worker-pools b/public/worker-pools index 90f35eb..5762746 100644 --- a/public/worker-pools +++ b/public/worker-pools @@ -40,7 +40,7 @@ a worker pool using goroutines and channels.

    - +
    package main
     
    @@ -150,7 +150,7 @@ channel to indicate that’s all the work we have.

    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.

    +goroutines is to use a WaitGroup.

    @@ -210,7 +210,7 @@ there are 3 workers operating concurrently.

    - Next example: WaitGroup. + Next example: WaitGroups.