一、案例
先看上面一段代码,子协程要在 100 个小时候退出,导致主协程始终卡在那边。
func TestCancel1(t *testing.T) {wg := sync.WaitGroup{}
wg.Add(1)
go func() {t.Log("goroutine 1")
time.Sleep(100 * time.Hour)
wg.Done()}()
wg.Wait()
t.Log("goroutine main")
}
输入:
可见主协程始终 期待状态,没发退出。
二、应用 context.WithTimeout,给协程一个退出工夫
咱们在上面的代码里,写了一个 context.WithTimeout 给 3 秒,3 秒后这个程序没有执行完就退出。
func TestTimeout(t *testing.T) {wg := sync.WaitGroup{}
wg.Add(1)
parentContext := context.Background()
cancelCtx, cancelFunc := context.WithTimeout(parentContext, time.Second*3)
go func(ctx context.Context) {
for {t.Log("goroutine 1")
select {case <-cancelCtx.Done():
wg.Done()
return
case <-time.After(time.Hour * 100):
wg.Done()}
}
}(cancelCtx)
wg.Wait()
cancelFunc()
t.Log("goroutine main")
}
三、应用 context.WithCancel,在子协程退出
func TestCancel2(t *testing.T) {wg := sync.WaitGroup{}
wg.Add(1)
parentContext := context.Background()
cancelCtx, cancelFunc := context.WithCancel(parentContext)
go func(ctx context.Context) {
for {
select {case <-cancelCtx.Done():
return
case <-time.After(time.Hour * 100):
cancelFunc()
wg.Done()
case <-time.After(time.Second * 3):
cancelFunc()
wg.Done()}
t.Log("goroutine 1")
}
}(cancelCtx)
wg.Wait()
t.Log("goroutine main")
}
输入:
goroutine 1
goroutine main