参考资料:
​​​golang服务器开发利器 context用法详解​​​​https://github.com/go-training/training/tree/master/example35-goroutine-with-context​​​​context使用​

控制并发的两种方式

  • 使用waitGroup
  • 使用context

场景1:多个goroutine执行同一件事

waitGroup使用

func main() {
var wg sync.WaitGroup

wg.Add(2)
go func() {
time.Sleep(2 * time.Second)
fmt.Println("job 1 done.")
wg.Done()
}()
go func() {
time.Sleep(1 * time.Second)
fmt.Println("job 2 done.")
wg.Done()
}()
wg.Wait()
fmt.Println("All Done.")
}
$ go run con3.go
job 2 done.
job 1 done.
All Done.

场景2: 当主动通知停止?如何做?

使用channel + select

package main

import (
"fmt"
"time"
)

func main() {
stop := make(chan bool)

go func() {
for {
select {
case <-stop:
fmt.Println("got the stop channel")
return
default:
fmt.Println("still working")
time.Sleep(1 * time.Second)
}
}
}()

time.Sleep(5 * time.Second)
fmt.Println("stop the gorutine")
stop <- true
time.Sleep(5 * time.Second)
}
$ go run con4.go
still working
still working
still working
still working
still working
stop the gorutine
got the stop channel

当多个goroutine或goroutine中有goroutine

go context处理单个请求的多个goroutine详解_github

package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())

go func() {
for {
select {
case <-ctx.Done():
fmt.Println("got the stop channel")
return
default:
fmt.Println("still working")
time.Sleep(1 * time.Second)
}
}
}()

time.Sleep(5 * time.Second)
fmt.Println("stop the gorutine")
cancel()
time.Sleep(5 * time.Second)
}
$ go run con5.go
still working
still working
still working
still working
still working
stop the gorutine
got the stop channel

多个goroutine

package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())

go worker(ctx, "node01")
go worker(ctx, "node02")
go worker(ctx, "node03")

time.Sleep(5 * time.Second)
fmt.Println("stop the gorutine")
cancel()
time.Sleep(5 * time.Second)
}

func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "got the stop channel")
return
default:
fmt.Println(name, "still working")
time.Sleep(1 * time.Second)
}
}
}
$ go run con6.go
node03 still working
node01 still working
node02 still working
node03 still working
node02 still working
node01 still working
node01 still working
node03 still working
node02 still working
node02 still working
node01 still working
node03 still working
node03 still working
node02 still working
node01 still working
stop the gorutine
node01 got the stop channel
node03 got the stop channel
node02 got the stop channel