- parameter supplied to the method 'Add' in the sync.WaitGroup struct must be equal
to the current running goroutine. no more, no less.
- if less than number of current running goroutine, it will leads to unexpected behavior.
- if more than number of current running goroutine, it will leads to deadlock.
// dirty and simple :))
package main
import (
"fmt"
"sync"
"time"
)
type Aggregator interface {
Add(j *Job)
Dispatch()
}
type Job struct {
text string
lower int
upper int
}
type Runner struct {
jobs []*Job
group *sync.WaitGroup
}
func (j *Job) outputText(group *sync.WaitGroup) {
for j.lower < j.upper {
time.Sleep(time.Millisecond)
fmt.Println(j.text)
j.lower++
}
group.Done()
}
func (r *Runner) Add(j *Job) {
r.jobs = append(r.jobs, j)
}
func (r *Runner) Dispatch() {
for _, v := range r.jobs {
go v.outputText(r.group)
}
r.group.Add(len(r.jobs))
r.group.Wait()
}
func main() {
r := Runner{jobs: make([]*Job, 0), group: new(sync.WaitGroup)}
r.Add(&Job{text: "hello", lower: 0, upper: 3})
r.Add(&Job{text: "world", lower: 0, upper: 5})
r.Add(&Job{text: "this is a shit", lower: 0, upper: 2})
r.Dispatch()
}
- if you don't ever yield to the main thread, your goroutines will perform in unexpected ways (or won't perform at all).
- if you call runtime.GOMAXPROCS with value 0, it doesn't change / alter the number of CPU cores that will be used to run
any number of existing goroutine.
- runtime.GOMAXPROCS value can read value from environment variable too. Look at the example below:
package main
import (
"fmt"
"runtime"
)
func main() {
// get current number of GOMAXPROCS
fmt.Printf("GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0))
}
# read from environment variable
shell~$ GOMAXPROCS=2 go run main.go
2