乐趣区

关于go:go-使用-context-退出子协程-goroutine

一、案例

先看上面一段代码,子协程要在 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
退出移动版