Welcome everyone to part 19 of the Go Language programming tutorial series, where we've been covering concurrency in Go, but have quickly come across a problem where our goroutines will not necessarily finish by the time our program does. We need a way to wait for them as necessary.
Besides waiting for your goroutines to finish like in our case, where they aren't dependent on eachother, there are also going to be times when you want to run a group of goroutines, wait for them to all finish, then run another group. Again, we need some way, other than an arbitrary sleep, to make this happen. To do it, we'll use the sync
package from the standard library.
Our code up to this point:
package main import ( "fmt" "time" ) func say(s string) { for i:=0; i < 3; i++ { time.Sleep(100*time.Millisecond) fmt.Println(s) } } func main() { go say("Hey") go say("there") time.Sleep(1000*time.Millisecond) }
This code works fine, but the time.Sleep(1000*time.Millisecond)
is unfortunate. Instead of sleeping, we're going to use sync.WaitGroup
. To begin, let's import sync
, and define the WaitGroup
variable:
package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup
Once we have a "wait group," we can add goroutines to this group:
func main() { wg.Add(1) go say("Hey") wg.Add(1) go say("there") }
We can add whatever we want, and then specify that we want to wait for this group of goroutines with wg.Wait()
func main() { wg.Add(1) go say("Hey") wg.Add(1) go say("there") wg.Wait() }
Now, the "wait group" only knows it needs to finish some goroutines, but it doesn't really know when or which ones. For this reason, we need our goroutine to tell the wait group it is done, with wg.Done
func say(s string) { for i:=0; i < 3; i++ { time.Sleep(100*time.Millisecond) fmt.Println(s) } wg.Done() }
Full code up to this point:
package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup func say(s string) { for i:=0; i < 3; i++ { time.Sleep(100*time.Millisecond) fmt.Println(s) } wg.Done() } func main() { wg.Add(1) go say("Hey") wg.Add(1) go say("there") wg.Wait() }
Awesome! This runs, and everything is right with the world!
...but what if, for whatever reason, the say
function breaks, and we never make it to wg.Done()
? That...could be problematic. In order to handle for this, we need to begin discussing defer
, panic
, and recover
, which we'll begin in the next tutorial.