在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
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
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) } } }
|
请发表评论