zoukankan      html  css  js  c++  java
  • 【Golang】Golang Context上下文包

    context介绍

      Golang里的Context包非常重要,Context包是在golang 1.7之后引入的,它主要是解决如何优雅的去控制子goroutine退出。

    控制并发的两种方式

      1. Waitgroup:

       适用于多个goroutine执行同一件事,然后一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。比如将一个大的任务拆解多个子任务。

    package main
    
    import (
       "fmt"
       "sync"
       "time"
    )
    
    func main()  {
        var wg sync.WaitGroup
        wg.Add(2)
        //job 1
        go func(){
            //暂停2秒
            time.Sleep(2 * time.Second)
            fmt.Println("job 1 done")
            wg.Done()//上面执行完毕后就会执行done
        }()
    
        //job 2
        go func(){
            //暂停1秒
            time.Sleep(1 * time.Second)
            fmt.Println("job 2 done")
            wg.Done()
        }()
    
        wg.Wait()//wait一直在阻塞直到等待所有job都完成
        fmt.Println("All Done")
    }

      执行结果

    songguojundeMacBook-Pro:context songguojun$ go run main.go 
    job 2 done
    job 1 done
    All Done

       上面的例子每个job都是自己跑直到跑完任务结束,如果外界要中断其执行,看看下面的例子。

    package main
    
    import (
       "fmt"
       "time"
       "sync"
    )
    
    var wg sync.WaitGroup
    var quitOut bool
    
    func worker() {
        defer wg.Done()
        //死循环
        for {
            fmt.Println("for running.")
            time.Sleep(1 * time.Second)
            if quitOut {//达到条件就退出
                break
            }
        }
    }
    
    func main()  {
        wg.Add(1)
        go worker()
        time.Sleep(5 * time.Second)
        //设置quitOut为true通知子goroutine退出
        quitOut = true
        wg.Wait()
        fmt.Println("running closed")
    }

    执行结果

    songguojundeMacBook-Pro:context songguojun$ go run main.go 
    for running.
    for running.
    for running.
    for running.
    for running.
    running closed

     下面的例子使用的是channel + select的方式。

    package main
    
    import (
       "fmt"
       "time"
    )
    
    func main()  {
        stop := make(chan bool) //chan初始化
        go func() {
            for {
                select {
                    //接受信息
                case <-stop:
                    fmt.Println("got the stop channel")
                    return    //这里如果写break只能跳出select而不能跳出for循环
                default:
                    fmt.Println("still working")
                    time.Sleep(1 * time.Second)
                }
            }
        }()
        
        time.Sleep(5 * time.Second)
        fmt.Println("stop the gorutine")
        //将true传递给stop
        stop <- true
        time.Sleep(5 * time.Second)
    }

    执行结果

    songguojundeMacBook-Pro:context songguojun$ go run main.go 
    still working
    still working
    still working
    still working
    still working
    stop the gorutine
    got the stop channel    #下面没有输出,就是已经结束gorutine了

      2. Context

        Context用于在一个主gorutine去通知子gorutine结束工作,上面的代码例子中,如果gorutine里嵌套gorutine,就是一个job中又包含一个job,这时候这种场景就需要用到Context

    package main
    
    import (
       "fmt"
       "time"
       "context"
    )
    
    func worker(ctx context.Context, name string) {
        go func() {
            for {
                select {
                case <-ctx.Done():   //Done是一个只读的chan
                    fmt.Println(name, "got the stop channel")
                    return
                default:
                    fmt.Println(name, "still working")
                    time.Sleep(1 * time.Second)
                }
            }
        }()
    }
    
    func main()  {
        ctx, cancel := context.WithCancel(context.Background())  //context.WithCancel表示创建一个取消函数
    
        go worker(ctx, "node1")
        go worker(ctx, "node2")
        go worker(ctx, "node3")
    
        time.Sleep(5 * time.Second)
        fmt.Println("stop the gorutine")
        //cancel方法可以将上面node1 node2 node3都停止掉
        cancel()
        time.Sleep(5 * time.Second)
    }

    执行结果

    songguojundeMacBook-Pro:context songguojun$ go run main.go 
    node3 still working
    node1 still working
    node2 still working
    node2 still working
    node1 still working
    node3 still working
    node2 still working
    node1 still working
    node3 still working
    node3 still working
    node1 still working
    node2 still working
    node2 still working
    node3 still working
    node1 still working
    stop the gorutine
    node1 got the stop channel
    node2 got the stop channel
    node3 got the stop channel
  • 相关阅读:
    使用图表控件
    XPath 语法规则入门
    用javascript生成日历控件
    .NET开发人员应该关注的七个开源项目
    浅谈软件技术的发展趋势及定位
    System.Runtime.InteropServices.Automation
    【摘录】手机操作系统三国时代的结束
    .NET的资源并不限于.resx文件,你可以采用任意存储形式[上篇] (转载)
    OSPaas征途(前言)
    .NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]
  • 原文地址:https://www.cnblogs.com/songgj/p/10949039.html
Copyright © 2011-2022 走看看