<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在 Go http包的Server中,每一個請求在都有一個對應的 goroutine 去處理。請求處理函數通常會啟動額外的 goroutine 用來訪問后端服務,比如數據庫和RPC服務。用來處理一個請求的 goroutine 通常需要訪問一些與請求特定的數據,比如終端用戶的身份認證信息、驗證相關的token、請求的截止時間。 當一個請求被取消或超時時,所有用來處理該請求的 goroutine 都應該迅速退出,然后系統才能釋放這些 goroutine 占用的資源。 在Google 內部,我們開發了 Context 包,專門用來簡化 對于處理單個請求的多個 goroutine 之間與請求域的數據、取消信號、截止時間等相關操作,這些操作可能涉及多個 API 調用。 context的數據結構是: ~~~go // A Context carries a deadline, cancelation signal, and request-scoped values // across API boundaries. Its methods are safe for simultaneous use by multiple // goroutines. type Context interface { // Done returns a channel that is closed when this `Context` is canceled // or times out. Done() <-chan struct{} // Err indicates why this Context was canceled, after the Done channel // is closed. Err() error // Deadline returns the time when this Context will be canceled, if any. Deadline() (deadline time.Time, ok bool) // Value returns the value associated with key or nil if none. Value(key interface{}) interface{} } ~~~ Context中的方法: * Done會返回一個channel,當該context被取消的時候,該channel會被關閉,同時對應的使用該context的routine也應該結束并返回。 * Context中的方法是協程安全的,這也就代表了在父routine中創建的context,可以傳遞給任意數量的routine并讓他們同時訪問。 * Deadline會返回一個超時時間,routine獲得了超時時間后,可以對某些io操作設定超時時間。 * Value可以讓routine共享一些數據,當然獲得數據是協程安全的。 這里需要注意一點的是在goroutine中使用context包的時候,通常我們需要在goroutine中新創建一個上下文的context,原因是:如果直接傳遞外部context到協層中,一個請求可能在主函數中已經結束,在goroutine中如果還沒有結束的話,會直接導致goroutine中的運行的被取消. ~~~go go func() { _, ctx, _ := log.FromContextOrNew(context.Background(), nil) }() ~~~ context.Background函數的返回值是一個空的context,經常作為樹的根結點,它一般由接收請求的第一個routine創建,不能被取消、沒有值、也沒有過期時間。 Background函數的聲明如下: ~~~go // Background returns an empty Context. It is never canceled, has no deadline, // and has no values. Background is typically used in main, init, and tests, // and as the top-level `Context` for incoming requests. func Background() Context ~~~ WithCancel 和 WithTimeout 函數 會返回繼承的 Context 對象, 這些對象可以比它們的父 Context 更早地取消。 當請求處理函數返回時,與該請求關聯的 Context 會被取消。 當使用多個副本發送請求時,可以使用 WithCancel取消多余的請求。 WithTimeout 在設置對后端服務器請求截止時間時非常有用。 下面是這三個函數的聲明: ~~~go // WithCancel returns a copy of parent whose Done channel is closed as soon as // parent.Done is closed or cancel is called. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) // A CancelFunc cancels a Context. type CancelFunc func() // WithTimeout returns a copy of parent whose Done channel is closed as soon as // parent.Done is closed, cancel is called, or timeout elapses. The new // Context's Deadline is the sooner of now+timeout and the parent's deadline, if // any. If the timer is still running, the cancel function releases its // resources. func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) ~~~ 調用CancelFunc對象將撤銷對應的Context對象,這樣父結點的所在的環境中,獲得了撤銷子節點context的權利,當觸發某些條件時,可以調用CancelFunc對象來終止子結點樹的所有routine。在子節點的routine中,需要判斷何時退出routine: ~~~go select { case <-cxt.Done(): // do some cleaning and return } ~~~ 根據cxt.Done()判斷是否結束。當頂層的Request請求處理結束,或者外部取消了這次請求,就可以cancel掉頂層context,從而使整個請求的routine樹得以退出。 WithDeadline和WithTimeout比WithCancel多了一個時間參數,它指示context存活的最長時間。如果超過了過期時間,會自動撤銷它的子context。所以context的生命期是由父context的routine和deadline共同決定的。 WithValue 函數能夠將請求作用域的數據與 Context 對象建立關系。聲明如下: ~~~go type valueCtx struct { Context key, val interface{} } func WithValue(parent Context, key, val interface{}) Context { if key == nil { panic("nil key") } ...... return &valueCtx{parent, key, val} } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } ~~~ WithValue返回parent的一個副本,該副本保存了傳入的`key/value`,而調用Context接口的Value(key)方法就可以得到val。注意在同一個context中設置`key/value`,若key相同,值會被覆蓋。 Context上下文數據的存儲就像一個樹,每個結點只存儲一個`key/value`對。WithValue()保存一個`key/value`對,它將父context嵌入到新的子context,并在節點中保存了`key/value`數據。Value()查詢key對應的value數據,會從當前context中查詢,如果查不到,會遞歸查詢父context中的數據。 值得注意的是,context中的上下文數據并不是全局的,它只查詢本節點及父節點們的數據,不能查詢兄弟節點的數據。 Context 使用原則: * 不要把Context放在結構體中,要以參數的方式傳遞。 * 以Context作為參數的函數方法,應該把Context作為第一個參數,放在第一位。 * 給一個函數方法傳遞Context的時候,不要傳遞nil,如果不知道傳遞什么,就使用context.TODO。 * Context的Value相關方法應該傳遞必須的數據,不要什么數據都使用這個傳遞。 * Context是線程安全的,可以放心的在多個goroutine中傳遞。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看