go 上下文context
Posted tigerzhouv587
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消。
WithTimeout
和WithDeadline
基本上一样,这个表示是超时自动取消,是多少时间后自动取消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)
以上是关于go 上下文context的主要内容,如果未能解决你的问题,请参考以下文章