一、案例

先看上面一段代码,子协程要在 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 1goroutine main