WaitGroup
var wg sync.WaitGroup

Racing Condition
Occurs when order of execution is NOT guaranteed.
problem
https://go.dev/play/p/DxHz6ia14dt
package main
import (
"fmt"
)
func main() {
var data int
go func() {
data++
}()
fmt.Printf("the value of data is %v\n", data)
fmt.Println("Done..")
}
solution
https://go.dev/play/p/l9CEVUT9xsc
package main
import (
"fmt"
"sync"
)
func main() {
// program to print the value as 1
// deterministically.
var wg sync.WaitGroup
var data int
wg.Add(1)
go func() {
defer wg.Done()
data++
}()
wg.Wait()
fmt.Printf("the value of data is %v\n", data)
fmt.Println("Done..")
}
Sequential Add vs Concurrency Add
Normal Add
func Add(numbers []int) int64 {
var sum int64
for _, n := range numbers {
sum += int64(n)
}
return sum
}
Concurrency Add
// AddConcurrent - concurrent code to add numbers
func AddConcurrent(numbers []int) int64 {
// Utilize all cores on machine
numOfCores := runtime.NumCPU()
runtime.GOMAXPROCS(numOfCores)
var sum int64
max := len(numbers)
sizeOfParts := max / numOfCores
var wg sync.WaitGroup
for i := 0; i < numOfCores; i++ {
// Divide the input into parts
start := i * sizeOfParts
end := start + sizeOfParts
part := numbers[start:end]
// Run computation for each part in seperate goroutine.
wg.Add(1)
go func(nums []int) {
defer wg.Done()
var partSum int64
// Calculate sum for each part
for _, n := range nums {
partSum += int64(n)
}
// Add sum of each part to cummulative sum
atomic.AddInt64(&sum, partSum)
}(part)
}
wg.Wait()
return sum
}
benchmark
go test -benchmem -run=none -bench=. MyGoNote/concurrency/02_Goroutines/01_exercises/03_waitgroup/count/counting -v -count=1
goos: darwin
goarch: amd64
pkg: MyGoNote/concurrency/02_Goroutines/01_exercises/03_waitgroup/count/counting
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
BenchmarkAdd
BenchmarkAdd-8 156 7223807 ns/op 512840 B/op 0 allocs/op
BenchmarkAddConcurrent
BenchmarkAddConcurrent-8 480 2098310 ns/op 167298 B/op 18 allocs/op
PASS
ok MyGoNote/concurrency/02_Goroutines/01_exercises/03_waitgroup/count/counting 6.251s
func BenchmarkAdd(b *testing.B) {
numbers := GenerateNumbers(1e7)
for i := 0; i < b.N; i++ {
Add(numbers)
}
}
func BenchmarkAddConcurrent(b *testing.B) {
numbers := GenerateNumbers(1e7)
for i := 0; i < b.N; i++ {
AddConcurrent(numbers)
}
}