只通过select监听超时信号,没有处理正常逻辑处理。
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
// 定义一个3s超时context 所有衍生出来的goroutine必须在3s内完成 否则会cancel掉
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go func() {
wg.Add(2)
go watch(ctx, 1)
go watch(ctx, 2)
wg.Wait()
}()
// 这里有问题,因为不管是超时还是未超时都会进入<-ctx.Done() 也就是都会等待3s 这不是我们想要的
select {
case <-ctx.Done():
fmt.Printf("watch %d %s\n", 0, ctx.Err())
}
fmt.Println("finished")
}
func watch(ctx context.Context, flag int) {
defer wg.Done()
func() {
fmt.Printf("doing something flag:%d\n", flag)
time.Sleep(10*time.Second)
fmt.Println("finished flag:", flag)
}()
}
很简单,就是在所有goroutine结束之后发送一个done信号给主goroutine,这样select就会监听到这个信号,从而安全退出。
// 增加done信号
done := make(chan struct{})
go func() {
wg.Add(2)
go watch(ctx, 1)
go watch(ctx, 2)
wg.Wait()
done <- struct{}{} // 发送done信号
}()
select {
case <-done: // 接受done信号
fmt.Println("Done")
case <-ctx.Done():
fmt.Printf("watch %d %s\n", 0, ctx.Err())
}