package main import ( "context" "fmt" "sync" "time" ) func routine(id int, ctx context.Context, msg chan int, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("routine ", id) ticker := time.NewTicker(1 * time.Second) for range ticker.C { select { case <-ctx.Done(): fmt.Println(ctx.Err(), id) return default: fmt.Println("recv msg ", id, <-msg) } } } func main() { var wg sync.WaitGroup msg := make(chan int, 10) //send msg for i := 0; i < 10; i++ { msg <- i } //ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) //ctx, cancel := context.WithCancel(context.Background()) defer cancel() for i := 1; i < 3; i++ { wg.Add(1) go routine(i, ctx, msg, &wg) } defer close(msg) //time.Sleep(3 * time.Second) //cancel() wg.Wait() fmt.Println("main exit") }
调用context 的WithCancel 方法时,需要主动调用cancel, 才能发送 Done,从而结束每个协程,而WithDeadline (WithTimeout 是对WithDeadline的封装) 因为有时间参数,不需要主动调用cancel.