• go 上下文context


    go控制并发有两种经典的方式,一种是WaitGroup,另外一种就是Context

    WaitGroup这种方式是控制多个goroutine同时完成

    func main() {
        var wg sync.WaitGroup
    
        wg.Add(2)
        go func() {
            time.Sleep(2*time.Second)
            fmt.Println("1号完成")
            wg.Done()
        }()
        go func() {
            time.Sleep(2*time.Second)
            fmt.Println("2号完成")
            wg.Done()
        }()
        wg.Wait()
        fmt.Println("好了,大家都干完了,放工")
    }

    channel 通知,根据channel阻塞的原理来进行goroutine控制

    func main() {
        stop := make(chan bool)
    
        go func() {
            for {
                select {
                case <-stop:
                    fmt.Println("监控退出,停止了...")
                    return
                default:
                    fmt.Println("goroutine监控中...")
                    time.Sleep(2 * time.Second)
                }
            }
        }()
    
        time.Sleep(10 * time.Second)
        fmt.Println("可以了,通知监控停止")
        stop<- true
        //为了检测监控过是否停止,如果没有监控输出,就表示停止了
        time.Sleep(5 * time.Second)
    
    }

    context

    在go服务器中,对于每个请求的request都是在单独的goroutine中进行的,处理一个request也可能设计多个goroutine之间的交互, 使用context可以使开发者方便的在这些goroutine里传递request相关的数据、取消goroutine的signal或截止日期。

    context接口如下

    type Context interface {
        Deadline() (deadline time.Time, ok bool)
    
        Done() <-chan struct{}
    
        Err() error
    
        Value(key interface{}) interface{}
    }

    Done 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知,告诉给context相关的函数要停止当前工作然后返回。当一个父operation启动一个goroutine用于子operation,这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。

    Err方法返回context为什么被取消。

    Deadline返回context何时会超时。

    Value返回context相关的数据。

    context 衍生方法

    func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
    func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
    func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
    func WithValue(parent Context, key, val interface{}) Context

    WithCancel函数,传递一个父Context作为参数,返回子Context,以及一个取消函数用来取消Context。WithDeadline函数,和WithCancel差不多,它会多传递一个截止时间参数,意味着到了这个时间点,会自动取消Context,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消。

    WithTimeoutWithDeadline基本上一样,这个表示是超时自动取消,是多少时间后自动取消Context的意思。

    WithValue函数和取消Context无关,它是为了生成一个绑定了一个键值对数据的Context,这个绑定的数据可以通过Context.Value方法访问到

    withCancle

    package main
     
    import (
        "context"
        "log"
        "os"
        "time"
    )
     
    var logg *log.Logger
     
    func someHandler() {
        ctx, cancel := context.WithCancel(context.Background())
        go doStuff(ctx)
     
    //10秒后取消doStuff
        time.Sleep(10 * time.Second)
        cancel()
     
    }
     
    //每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
    func doStuff(ctx context.Context) {
        for {
            time.Sleep(1 * time.Second)
            select {
            case <-ctx.Done():
                logg.Printf("done")
                return
            default:
                logg.Printf("work")
            }
        }
    }
     
    func main() {
        logg = log.New(os.Stdout, "", log.Ltime)
        someHandler()
        logg.Printf("down")
    }

    withDeadline

    package main
    
    import (
        "context"
        "log"
        "os"
        "time"
    )
    
    var logg *log.Logger
    
    func timeoutHandler() {
        ctx, cancel := context.WithDeadline(context.Background(),time.Now().Add(5*time.Second))
        go doStuff(ctx)
    
    //10秒后取消doStuff
        time.Sleep(10 * time.Second)
        cancel()
    
    }
    
    //每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
    func doStuff(ctx context.Context) {
        for {
            time.Sleep(1 * time.Second)
            select {                          
            case <-ctx.Done():
                logg.Printf("done")
                return
            default:
                logg.Printf("work")
            }
        }
    }
    
    func main() {
        logg = log.New(os.Stdout, "", log.Ltime)
        timeoutHandler()
        logg.Printf("down")
    }

    withtimeout

    package main
    
    import (
        "context"
        "log"
        "os"
        "time"
    )
    
    var logg *log.Logger
    
    func timeoutHandler() {
        ctx, cancel := context.WithTimeout(context.Background(),5*time.Second)
        go doStuff(ctx)
    
    //10秒后取消doStuff
        time.Sleep(10 * time.Second)
        cancel()
    
    }
    
    //每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
    func doStuff(ctx context.Context) {
        for {
            time.Sleep(1 * time.Second)
            select {                          
            case <-ctx.Done():
                logg.Printf("done")
                return
            default:
                logg.Printf("work")
            }
        }
    }
    
    func main() {
        logg = log.New(os.Stdout, "", log.Ltime)
        timeoutHandler()
        logg.Printf("down")
    }

    withvalue

    package main
    
    import (
        "context"
        "fmt"
        "time"
    )
        
    
    
    var key string="name"
    
    func main() {
        ctx, cancel := context.WithCancel(context.Background())
        //附加值
        valueCtx:=context.WithValue(ctx,key,"【监控1】")
        go watch(valueCtx)
        time.Sleep(10 * time.Second)
        fmt.Println("可以了,通知监控停止")
        cancel()
        //为了检测监控过是否停止,如果没有监控输出,就表示停止了
        time.Sleep(5 * time.Second)
    }
    
    func watch(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():
                //取出值
                fmt.Println(ctx.Value(key),"监控退出,停止了...")
                return
            default:
                //取出值
                fmt.Println(ctx.Value(key),"goroutine监控中...")
                time.Sleep(2 * time.Second)
            }
        }
    }
  • 相关阅读:
    二分模板
    洛谷P1631序列合并(二分答案经典好题,或优先队列堆+数学优化,或有序表一一顺序比较)
    洛谷P1498南蛮图腾(找规律,输出图形题技巧)
    洛谷P2611信息传递(思维环形题,并查集)
    关于环的问题
    洛谷P1064金明的预算方案(好题难题,依赖的背包dp,或计算拓扑先后顺序+记忆化搜索)
    2018.11.4薛猫杯比赛
    大数加减法模板
    洛谷p1060开心的金明(dp,正向暴力递归+剪枝或记忆化)
    洛谷二分答案问题
  • 原文地址:https://www.cnblogs.com/tigerzhouv587/p/11514286.html
Copyright © 2020-2023  润新知