Goroutines
Goroutines can access to variables from outer scope, but it is bad practice. Variable will be accessed on invoking time not defined. So if variable is changed after defining goroutine you can see unexpected behavior:
func main() {
var msg = "hello"
go func() {
fmt.Println(msg)
}()
msg = "goodbye"
// timeout required to let the gororoutine run otherwise program will shut down without invoking gorotine
time.Sleep(100 * time.Millisecond)
// Output:
// goodbye
}
To avoid that you can pass variable (by value):
func main() {
var msg = "hello"
go func(msg string) {
fmt.Println(msg)
}(msg)
msg = "goodbye"
// timeout required to let the gororoutine run otherwise program will shut down without invoking gorotine
time.Sleep(100 * time.Millisecond)
// Output:
// goodbye
}
To synchronize main function with goroutines use sync.waitGroup:
var wc = sync.WaitGroup{}
func main() {
var msg = "hello"
// Here is 1 is the count of goroutines to watch+
wg.Add(1)
go func(msg string) {
fmt.Println(msg)
wg.Done()
}(msg)
wg.Wait()
}
Waitgroup doesn't let synchronize goroutines. They are running as fast as they can so there is no queue as expected because of concurrency:
var wg = sync.WaitGroup{}
var counter = 0
// Output will be different everytime you call func
func main() {
for i := 0; i < 10; i++ {
// Here is 2 because we invoking 2 goroutines
wg.Add(2)
go sayHello()
go increment()
}
wg.Wait()
// Output:
// Hello, counter is: 0
// Hello, counter is: 3
// Hello, counter is: 4
// Hello, counter is: 5
// Hello, counter is: 0
// Hello, counter is: 2
// Hello, counter is: 10
// Hello, counter is: 8
// Hello, counter is: 6
// Hello, counter is: 3
}
func sayHello() {
fmt.Printf("Hello, counter is: %d\n", counter)
wg.Done()
}
func increment() {
counter++
wg.Done()
}
-race flag to run command. Example: go run -race main.go
Mutex example:
package main
import (
"fmt"
"sync"
"runtime"
)
var wg = sync.WaitGroup{}
var counter = 0
func main() {
// Set maximum CPU threads to 100
runtime.GOMAXPROCS(100)
for i := 0; i < 10; i++ {
wg.Add(2)
go sayHello()
go increment()
}
wg.Wait()
// Output:
// Hello, counter is: 0
// Hello, counter is: 1
// Hello, counter is: 2
// Hello, counter is: 3
// Hello, counter is: 4
// Hello, counter is: 5
// Hello, counter is: 6
// Hello, counter is: 7
// Hello, counter is: 8
// Hello, counter is: 9
}
func sayHello() {
fmt.Printf("Hello, counter is: %d\n", counter)
wg.Done()
}
func increment() {
counter++
wg.Done()
}