https://www.liwenzhou.com/posts/Go/go_context/
1. 主goroutine如何通知子goroutine退出
1.1 使用全局变量
package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup // 使用全局变量来通知子goroutine退出 // 主goroutine来设置notify的值 var notify bool func f() { defer wg.Done() for { fmt.Println("==") time.Sleep(time.Millisecond * 500) if notify { break } } } func main() { wg.Add(1) go f() time.Sleep(time.Second * 5) // 如何通知子goroutine退出 notify = true wg.Wait() }
1.2 使用channel
package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup var exitChan = make(chan bool, 1) func f() { defer wg.Done() FORLOOP: for { fmt.Println("==") time.Sleep(time.Millisecond * 500) select { case <-exitChan: break FORLOOP default: } } } func main() { wg.Add(1) go f() time.Sleep(time.Second * 5) // 如何通知子goroutine退出 exitChan <- true wg.Wait() }
1.3 使用context(为了协同开发,官方弄了这个context)
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup func f2(ctx context.Context) { defer wg.Done() FORLOOP: for { fmt.Println("保德路") time.Sleep(time.Millisecond * 500) select { case <-ctx.Done(): break FORLOOP default: } } } func f(ctx context.Context) { defer wg.Done() // f2私有f调的,context也是由f给的 // 在主goroutine调cancel()的时候都会传到f2,不管有多少级 go f2(ctx) FORLOOP: for { fmt.Println("==") time.Sleep(time.Millisecond * 500) select { case <-ctx.Done(): break FORLOOP default: } } } func main() { ctx, cancel := context.WithCancel(context.Background()) wg.Add(1) go f(ctx) time.Sleep(time.Second * 5) // 如何通知子goroutine退出 cancel() // 往ctx.Done()写一个空的结构体,拿到结构体就知道要退出了 wg.Wait() }