<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                在Go中http包的Server中,每一個請求在都有一個對應的goroutine去處理。請求處理函數通常會啟動額外的goroutine用來訪問后端服務,比如數據庫和RPC服務。用來處理一個請求的goroutine通常需要訪問一些與請求特定的數據,比如終端用戶的身份認證信息,驗證相關的令牌,請求的截止時間。然后系統才能釋放這些goroutine占用的資源。 在Google內部,開發了Context包,專門用來簡化對于處理單個請求的多個goroutine之間與請求域的數據,取消信號,截止時間等相關操作,這些操作可能涉及多個API調用。 ~~~ go get golang.org/x/net/context命令獲取這個包。 ~~~ 注意: 使用時遵循context規則 ~~~ 1. 不要將 Context 放入結構體,Context應該作為第一個參數傳 入,命名為ctx。 2. 即使函數允許,也不要傳入nil的 Context。如果不知道用哪種 Context,可以使用context.TODO()。 3. 使用context的Value相關方法,只應該用于在程序和接口中傳遞 和請求相關數據,不能用它來傳遞一些可選的參數 4. 相同的 Context 可以傳遞給在不同的goroutine;Context 是 并發安全的。 ~~~ Context結構 ~~~ type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} } Deadline() 返回一個time.Time,是當前 Context 的應該結束的時間,ok 表示是否有 deadline Done() 返回一個struct{}類型的只讀 channel Err() 返回 Context 被取消時的錯誤 Value(key interface{}) 是 Context 自帶的 K-V 存儲功能 // Deadline會返回一個超時時間,Goroutine獲得了超時時間后,例如可以對某些io操作設定超時時間。 // Done方法返回一個信道(channel),當Context被撤銷或過期時,該信道是關閉的,即它是一個表示Context是否已關閉的信號。 // 當Done信道關閉后,Err方法表明Context被撤的原因。 // Value可以讓Goroutine共享一些數據,當然獲得數據是協程安全的。但使用這些數據的時候要注意同步,比如返回了一個map,而這個map的讀寫則要加鎖。 ~~~ 網絡請求超時控制 ~~~ package main import ( "context" "fmt" "io/ioutil" "net/http" "time" ) type Result struct { r *http.Response err error } func process() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) //釋放資源 defer cancel() tr := &http.Transport{} client := &http.Client{Transport: tr} resultChan := make(chan Result, 1) //發起請求 req, err := http.NewRequest("GET", "http://www.baidu.com", nil) // req, err := http.NewRequest("GET", "http://www.google.com", nil) if err != nil { fmt.Println("http request failed, err:", err) return } /* func (c *Client) Do(req *Request) (*Response, error) */ go func() { resp, err := client.Do(req) pack := Result{r: resp, err: err} //將返回信息寫入管道(正確或者錯誤的) resultChan <- pack }() select { case <-ctx.Done(): tr.CancelRequest(req) er := <-resultChan fmt.Println("Timeout!", er.err) case res := <-resultChan: defer res.r.Body.Close() out, _ := ioutil.ReadAll(res.r.Body) fmt.Printf("Server Response: %s", out) } return } func main() { process() } ~~~ 如果修改下代碼: ~~~ req, err := http.NewRequest("GET", "http://google.com", nil) ~~~ 請求超時,輸出日志信息如下: ~~~ Timeout! Get http://www.google.com: net/http: request canceled while waiting for connection ~~~ WithValue 傳遞元數據: ~~~ package main import ( "context" "fmt" ) func process(ctx context.Context) { ret,ok := ctx.Value("trace_id").(int) if !ok { ret = 21342423 } fmt.Printf("ret:%d\n", ret) s , _ := ctx.Value("session").(string) fmt.Printf("session:%s\n", s) } func main() { ctx := context.WithValue(context.Background(), "trace_id", 13483434) ctx = context.WithValue(ctx, "session", "sdlkfjkaslfsalfsafjalskfj") process(ctx) } ~~~ 輸出結果: ~~~ ret:13483434 session:sdlkfjkaslfsalfsafjalskfj ~~~ 通過Context我們也可以傳遞一些必須的元數據,這些數據會附加在Context上以供使用。 ~~~ 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) } } } ~~~ 輸出結果: ~~~ 【監控1】 goroutine監控中... 【監控1】 goroutine監控中... 【監控1】 goroutine監控中... 【監控1】 goroutine監控中... 【監控1】 goroutine監控中... 可以了,通知監控停止 【監控1】 監控退出,停止了... ~~~ 超時控制 WithDeadline ~~~ package main import ( "context" "fmt" "time" ) func main() { d := time.Now().Add(4 * time.Second) // d := time.Now().Add(2 * time.Second) ctx, cancel := context.WithDeadline(context.Background(), d) defer cancel() select { case <-time.After(3 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) } } ~~~ 輸出結果: ~~~ overslept ~~~ 如果將上面代碼修改為: ~~~ d := time.Now().Add(2 * time.Second) ~~~ 輸出結果: ~~~ context deadline exceeded ~~~ WithCancel 我們來了解一個利用context結束goroutine的demo ~~~ package main import ( "context" "fmt" "time" ) /* 創建一個管道chan,啟動goroutine for循環存數據 **/ func gen(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): //執行defer cancel操作后,就會執行到該select入庫 fmt.Println("i exited") return // returning not to leak the goroutine case dst <- n: n++ } } }() return dst } func test() { ctx, cancel := context.WithCancel(context.Background()) //當取數據n == 5時候,執行defer cancel操作 defer cancel() intChan := gen(ctx) for n := range intChan { fmt.Println(n) if n == 5 { break } } } func main() { test() time.Sleep(time.Second * 5) } ~~~ 輸出結果: ~~~ 1 2 3 4 5 i exited ~~~
                  <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>

                              哎呀哎呀视频在线观看