久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      詳解Golang的context

      下面由golang教程欄目給大家詳解Golang的context,希望對需要的朋友有所幫助!

      詳解Golang的context

      前言

      是的,今天本來還想出去玩的。買了動車票,然后又睡過頭了。。沒辦法,可能是天意,只好總結(jié)一下golang的context,希望能與context之間做一個了斷。

      公司里頭大家寫各種服務(wù),必須需要將Context作為第一個參數(shù),剛開始以為主要用于全鏈路排查跟蹤。但是隨著接觸多了,原來不止于此。

      正文

      1.context詳解

      1.1 產(chǎn)生背景

      在go的1.7之前,context還是非編制的(包golang.org/x/net/context中),golang團隊發(fā)現(xiàn)context這個東西還挺好用的,很多地方也都用到了,就把它收編了,1.7版本正式進入標(biāo)準(zhǔn)庫。

      context常用的使用姿勢:
      1.web編程中,一個請求對應(yīng)多個goroutine之間的數(shù)據(jù)交互
      2.超時控制
      3.上下文控制

      1.2 context的底層結(jié)構(gòu)

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

      這個就是Context的底層數(shù)據(jù)結(jié)構(gòu),來分析下:

      字段 含義
      Deadline 返回一個time.Time,表示當(dāng)前Context應(yīng)該結(jié)束的時間,ok則表示有結(jié)束時間
      Done 當(dāng)Context被取消或者超時時候返回的一個close的channel,告訴給context相關(guān)的函數(shù)要停止當(dāng)前工作然后返回了。(這個有點像全局廣播)
      Err context被取消的原因
      Value context實現(xiàn)共享數(shù)據(jù)存儲的地方,是協(xié)程安全的(還記得之前有說過map是不安全的?所以遇到map的結(jié)構(gòu),如果不是sync.Map,需要加鎖來進行操作)

      同時包中也定義了提供cancel功能需要實現(xiàn)的接口。這個主要是后文會提到的“取消信號、超時信號”需要去實現(xiàn)。

      // A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { 	cancel(removeFromParent bool, err error) 	Done() <-chan struct{} }

      那么庫里頭提供了4個Context實現(xiàn),來供大家玩耍

      實現(xiàn) 結(jié)構(gòu)體 作用
      emptyCtx type emptyCtx int 完全空的Context,實現(xiàn)的函數(shù)也都是返回nil,僅僅只是實現(xiàn)了Context的接口
      cancelCtx type cancelCtx struct {
      Context
      mu sync.Mutex
      done chan struct{}

      children map[canceler]struct{}
      err error
      }

      繼承自Context,同時也實現(xiàn)了canceler接口
      timerCtx type timerCtx struct {
      cancelCtx
      timer *time.Timer // Under cancelCtx.mu.
      deadline time.Time
      }
      繼承自cancelCtx,增加了timeout機制
      valueCtx type valueCtx struct {
      Context
      key, val interface{}
      }
      存儲鍵值對的數(shù)據(jù)

      1.3 context的創(chuàng)建

      為了更方便的創(chuàng)建Context,包里頭定義了Background來作為所有Context的根,它是一個emptyCtx的實例。

      var (     background = new(emptyCtx)     todo       = new(emptyCtx) //  )  func Background() Context {     return background }

      你可以認(rèn)為所有的Context是樹的結(jié)構(gòu),Background是樹的根,當(dāng)任一Context被取消的時候,那么繼承它的Context 都將被回收。

      2.context實戰(zhàn)應(yīng)用

      2.1 WithCancel

      實現(xiàn)源碼:

      func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 	c := newCancelCtx(parent) 	propagateCancel(parent, &c) 	return &c, func() { c.cancel(true, Canceled) } }

      實戰(zhàn)場景:
      執(zhí)行一段代碼,控制執(zhí)行到某個度的時候,整個程序結(jié)束。

      吃漢堡比賽,奧特曼每秒吃0-5個,計算吃到10的用時
      實戰(zhàn)代碼:

      func main() { 	ctx, cancel := context.WithCancel(context.Background()) 	eatNum := chiHanBao(ctx) 	for n := range eatNum { 		if n >= 10 { 			cancel() 			break 		} 	}  	fmt.Println("正在統(tǒng)計結(jié)果。。。") 	time.Sleep(1 * time.Second) }  func chiHanBao(ctx context.Context) <-chan int { 	c := make(chan int) 	// 個數(shù) 	n := 0 	// 時間 	t := 0 	go func() { 		for { 			//time.Sleep(time.Second) 			select { 			case <-ctx.Done(): 				fmt.Printf("耗時 %d 秒,吃了 %d 個漢堡 n", t, n) 				return 			case c <- n: 				incr := rand.Intn(5) 				n += incr 				if n >= 10 { 					n = 10 				} 				t++ 				fmt.Printf("我吃了 %d 個漢堡n", n) 			} 		} 	}()  	return c }

      輸出:

      我吃了 1 個漢堡 我吃了 3 個漢堡 我吃了 5 個漢堡 我吃了 9 個漢堡 我吃了 10 個漢堡 正在統(tǒng)計結(jié)果。。。 耗時 6 秒,吃了 10 個漢堡

      2.2 WithDeadline & WithTimeout

      實現(xiàn)源碼:

      func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { 	if cur, ok := parent.Deadline(); ok && cur.Before(d) { 		// The current deadline is already sooner than the new one. 		return WithCancel(parent) 	} 	c := &timerCtx{ 		cancelCtx: newCancelCtx(parent), 		deadline:  d, 	} 	propagateCancel(parent, c) 	dur := time.Until(d) 	if dur <= 0 { 		c.cancel(true, DeadlineExceeded) // deadline has already passed 		return c, func() { c.cancel(true, Canceled) } 	} 	c.mu.Lock() 	defer c.mu.Unlock() 	if c.err == nil { 		c.timer = time.AfterFunc(dur, func() { 			c.cancel(true, DeadlineExceeded) 		}) 	} 	return c, func() { c.cancel(true, Canceled) } }  func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 	return WithDeadline(parent, time.Now().Add(timeout)) }

      實戰(zhàn)場景:
      執(zhí)行一段代碼,控制執(zhí)行到某個時間的時候,整個程序結(jié)束。

      吃漢堡比賽,奧特曼每秒吃0-5個,用時10秒,可以吃多少個
      實戰(zhàn)代碼:

      func main() {     // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10)) 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 	chiHanBao(ctx) 	defer cancel() }  func chiHanBao(ctx context.Context) { 	n := 0 	for { 		select { 		case <-ctx.Done(): 			fmt.Println("stop n") 			return 		default: 			incr := rand.Intn(5) 			n += incr 			fmt.Printf("我吃了 %d 個漢堡n", n) 		} 		time.Sleep(time.Second) 	} }

      輸出:

      我吃了 1 個漢堡 我吃了 3 個漢堡 我吃了 5 個漢堡 我吃了 9 個漢堡 我吃了 10 個漢堡 我吃了 13 個漢堡 我吃了 13 個漢堡 我吃了 13 個漢堡 我吃了 14 個漢堡 我吃了 14 個漢堡 stop

      2.3 WithValue

      實現(xiàn)源碼:

      func WithValue(parent Context, key, val interface{}) Context { 	if key == nil { 		panic("nil key") 	} 	if !reflect.TypeOf(key).Comparable() { 		panic("key is not comparable") 	} 	return &valueCtx{parent, key, val} }

      實戰(zhàn)場景:
      攜帶關(guān)鍵信息,為全鏈路提供線索,比如接入elk等系統(tǒng),需要來一個trace_id,那WithValue就非常適合做這個事。
      實戰(zhàn)代碼:

      func main() { 	ctx := context.WithValue(context.Background(), "trace_id", "88888888") 	// 攜帶session到后面的程序中去 	ctx = context.WithValue(ctx, "session", 1)  	process(ctx) }  func process(ctx context.Context) { 	session, ok := ctx.Value("session").(int) 	fmt.Println(ok) 	if !ok { 		fmt.Println("something wrong") 		return 	}  	if session != 1 { 		fmt.Println("session 未通過") 		return 	}  	traceID := ctx.Value("trace_id").(string) 	fmt.Println("traceID:", traceID, "-session:", session) }

      輸出:

      traceID: 88888888 -session: 1

      3.context建議

      不多就一個。

      Context要是全鏈路函數(shù)的第一個參數(shù)

      func myTest(ctx context.Context)  {     ... }

      (寫好了竟然忘記發(fā)送了。。。汗)

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號