关于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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理