goroutine的结束与通信

结束

两种方法用select+channel的方法,结合WaitGroup可以同时控制多个goroutine结束,也可以在channel中传入time.After的定时器,二是利用Context里的取消函数cancel来处理,

感觉只利用select+channel+定时器进行监控协程不是很完美,需要结合context的cancel来实现,

参考:https://geektutu.com/post/hpg-timeout-goroutine.html

https://blog.csdn.net/weixin_40910614/article/details/121927730?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.no_search_link&utm_relevant_index=8

通信

通信实际上就是在不同goroutine间传递数据,一是用channel传递数据,二是用context中的WithValue添加数据,用Value取数据,利用ctx.Done()监控,

type favContextKey string

func main() {
    wg := &sync.WaitGroup{}
    values := []string{"https://www.baidu.com/", "https://www.zhihu.com/"}
    ctx, cancel := context.WithCancel(context.Background())
    for _, url := range values {
        wg.Add( 1)
        // 父节点向子节点传递ctx时,用WithValue绑定了一k-v对来进行数据的传递,
        subCtx := context.WithValue(ctx, favContextKey("url"), url)
        go reqURL(subCtx, wg)
    }
    go func() {
        time.Sleep(time.Second * 3  )
        cancel()
    }()
    wg.Wait()
    fmt.Println("exit main goroutine")
}
func reqURL(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    // 利用Value函数从传入的ctx中取出值,进而实现了协程通信,
    url, _ := ctx.Value(favContextKey("url")).(string)
    for {
        select {
        // 根节点取消的时候,这个Done里面的chan会close,case就会收到消息,
        case <-ctx.Done():
            fmt.Printf("stop getting url:%s\n", url)
            return
        default:
            r, err := http.Get(url)
            if r.StatusCode == http.StatusOK && err == nil {
                body, _ := ioutil.ReadAll(r.Body)
                subCtx := context.WithValue(ctx, favContextKey("resp"), fmt.Sprintf("%s%x", url, md5.Sum(body)))
                wg.Add(1 )
                go showResp(subCtx, wg)
            }
            r.Body.Close()
            //启动子goroutine是为了不阻塞当前goroutine,这里在实际场景中可以去执行其他逻辑,这里为了方便直接sleep一秒
            // doSometing()
            time.Sleep(time.Second * 1 )
        }
    }
}
func showResp(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case <-ctx.Done():
            fmt.Println("stop showing resp")
            return
        default:
            //子goroutine里一般会处理一些IO任务,如读写数据库或者rpc调用,这里为了方便直接把数据打印
            fmt.Println("printing ", ctx.Value(favContextKey("resp")))
            time.Sleep(time.Second * 1 )
        }
    }
}
View Code

参考:https://cloud.tencent.com/developer/article/1135275

posted on 2021-01-06 12:18  吃我一枪  阅读(95)  评论(0编辑  收藏  举报

导航