日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Go語言Context應用全攻略:異步編程利器

來源: 責編: 時間:2023-11-06 08:53:13 238觀看
導讀概述在 Go 語言中,Context(上下文)是一個非常重要的概念,特別是在處理請求時。允許在請求的整個生命周期內傳遞數據、控制請求的取消、處理超時等。本文將介紹 Go 語言中 Context 的使用,幫助更好地理解與處理請求的傳遞與

概述

在 Go 語言中,Context(上下文)是一個非常重要的概念,特別是在處理請求時。9x328資訊網——每日最新資訊28at.com

允許在請求的整個生命周期內傳遞數據、控制請求的取消、處理超時等。9x328資訊網——每日最新資訊28at.com

本文將介紹 Go 語言中 Context 的使用,幫助更好地理解與處理請求的傳遞與控制。9x328資訊網——每日最新資訊28at.com

主要內容包括9x328資訊網——每日最新資訊28at.com

Context 基礎9x328資訊網——每日最新資訊28at.com

Context 創建與傳遞9x328資訊網——每日最新資訊28at.com

Context 的超時與取消9x328資訊網——每日最新資訊28at.com

Context 的鏈式操作9x328資訊網——每日最新資訊28at.com

Context 在并發中的應用9x328資訊網——每日最新資訊28at.com

Context 的應用場景9x328資訊網——每日最新資訊28at.com

最佳實踐與注意事項9x328資訊網——每日最新資訊28at.com

1. Context 基礎

在 Go 語言中,context.Context 接口定義了一個請求的上下文。9x328資訊網——每日最新資訊28at.com

它包含了請求的截止時間、取消信號和請求的數據。9x328資訊網——每日最新資訊28at.com

使用 Context 可以在請求之間有效地傳遞數據,同時也可以控制請求的生命周期。9x328資訊網——每日最新資訊28at.com

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

Context 接口包含了四個方法:Deadline() 返回 Context 的截止時間9x328資訊網——每日最新資訊28at.com

Done() 返回一個通道,它會在 Context 被取消或超時時關閉9x328資訊網——每日最新資訊28at.com

Err() 返回 Context 的錯誤信息,Value(key) 返回 Context 中與 key 關聯的值。9x328資訊網——每日最新資訊28at.com

2. Context 創建與傳遞

2.1 創建和傳遞 Context

package mainimport (  "context"  "fmt"  "time")func main() {  // 創建一個根Context  rootContext := context.Background()  // 創建一個帶有超時時間的Context,這里設置超時時間為2秒  ctx, cancel := context.WithTimeout(rootContext, 2*time.Second)  defer cancel()  // 在新的goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(3 * time.Second):      fmt.Println("任務完成")    case <-ctx.Done():      fmt.Println("任務取消或超時")    }  }(ctx)    // 等待一段時間,模擬程序運行  time.Sleep(5 * time.Second)}

在這個例子中,創建了一個帶有 2 秒超時時間的 Context,并在一個新的 goroutine 中執行一個任務。9x328資訊網——每日最新資訊28at.com

在主 goroutine 中,等待了 5 秒,因此任務在超時之前完成,所以會輸出"任務完成"。9x328資訊網——每日最新資訊28at.com

2.2 使用 WithValue 傳遞數據

package mainimport (  "context"  "fmt")type key stringfunc main() {  // 創建一個根Context  rootContext := context.Background()  // 使用WithValue傳遞數據  ctx := context.WithValue(rootContext, key("userID"), 123)  // 在子函數中獲取傳遞的數據  getUserID(ctx)}func getUserID(ctx context.Context) {  // 從Context中獲取數據  if userID, ok := ctx.Value(key("userID")).(int); ok {    fmt.Println("UserID:", userID)  } else {    fmt.Println("UserID不存在")  }}

在這個示例中,使用 WithValue 方法在 Context 中傳遞了一個 userID 的值,并在 getUserID 函數中成功獲取并打印了這個值。9x328資訊網——每日最新資訊28at.com

3. Context 的超時與取消

3.1 設置請求超時時間

package mainimport (  "context"  "fmt"  "time")func main() {  // 創建一個根Context  rootContext := context.Background()  // 創建一個超時時間為2秒的Context  timeoutCtx, _ := context.WithTimeout(rootContext, 2*time.Second)  // 創建一個手動取消的Context  cancelCtx, cancel := context.WithCancel(rootContext)  defer cancel()  // 在新的goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(3 * time.Second):      fmt.Println("任務完成")    case <-ctx.Done():      fmt.Println("任務取消或超時")    }  }(timeoutCtx)  // 在另一個goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(1 * time.Second):      fmt.Println("另一個任務完成")    case <-ctx.Done():      fmt.Println("另一個任務取消")    }  }(cancelCtx)  // 等待一段時間,模擬程序運行  time.Sleep(5 * time.Second)}

在上面例子中,用 WithTimeout 方法創建了一個帶有 2 秒超時時間的 Context。9x328資訊網——每日最新資訊28at.com

在任務的 goroutine 中,用 select 語句監聽了超時和 Context 的取消兩個事件,以便及時響應。9x328資訊網——每日最新資訊28at.com

3.2 處理請求取消

package mainimport (  "context"  "fmt"  "time")func main() {  // 創建一個根Context  rootContext := context.Background()  // 創建一個可以手動取消的Context  ctx, cancel := context.WithCancel(rootContext)  defer cancel()  // 在新的goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(3 * time.Second):      fmt.Println("任務完成")    case <-ctx.Done():      fmt.Println("任務取消")    }  }(ctx)  // 等待一段時間,手動取消任務  time.Sleep(2 * time.Second)  cancel()  // 等待一段時間,模擬程序運行  time.Sleep(1 * time.Second)}

在上面例子中,使用 WithCancel 方法創建了一個可以手動取消的 Context。9x328資訊網——每日最新資訊28at.com

在主函數中,等待了 2 秒后,手動調用 cancel 函數取消了任務。9x328資訊網——每日最新資訊28at.com

這時,在任務的 goroutine 中,ctx.Done() 會接收到取消信號,從而退出任務。9x328資訊網——每日最新資訊28at.com

4. Context 的鏈式操作

在實際應用中,可能需要將多個 Context 串聯起來使用。9x328資訊網——每日最新資訊28at.com

Go 語言的 Context 提供了 WithCancel、WithDeadline、WithTimeout 等方法。9x328資訊網——每日最新資訊28at.com

可以用這些方法實現多個 Context 的協同工作。9x328資訊網——每日最新資訊28at.com

package mainimport (  "context"  "fmt"  "time")func main() {  // 創建一個根Context  rootContext := context.Background()  // 創建一個超時時間為2秒的Context  timeoutCtx, _ := context.WithTimeout(rootContext, 2*time.Second)  // 創建一個手動取消的Context  cancelCtx, cancel := context.WithCancel(rootContext)  defer cancel()  // 在新的goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(3 * time.Second):      fmt.Println("任務完成")    case <-ctx.Done():      fmt.Println("任務取消或超時")    }  }(timeoutCtx)  // 在另一個goroutine中執行任務  go func(ctx context.Context) {    select {    case <-time.After(1 * time.Second):      fmt.Println("另一個任務完成")    case <-ctx.Done():      fmt.Println("另一個任務取消")    }  }(cancelCtx)  // 等待一段時間,模擬程序運行  time.Sleep(5 * time.Second)}

在示例中,創建了一個帶有 2 秒超時時間的 Context 和一個可以手動取消的 Context,然后分別傳遞給兩個不同的任務。9x328資訊網——每日最新資訊28at.com

在主函數中,等待了 5 秒,超時時間為 2 秒,因此第一個任務會因超時而取消,第二個任務則會在 1 秒后完成。9x328資訊網——每日最新資訊28at.com

5. Context 在并發中的應用

5.1 使用 Context 控制多個協程

package mainimport (  "context"  "fmt"  "sync"  "time")func main() {  // 創建一個根Context  rootContext := context.Background()  // 創建一個可以手動取消的Context  ctx, cancel := context.WithCancel(rootContext)  defer cancel()  // 使用WaitGroup等待所有任務完成  var wg sync.WaitGroup  // 啟動多個協程執行任務  for i := 0; i < 5; i++ {    wg.Add(1)    go func(id int) {      defer wg.Done()      select {      case <-time.After(time.Duration(id) * time.Second):        fmt.Println("任務", id, "完成")      case <-ctx.Done():        fmt.Println("任務", id, "取消")      }    }(i)  }  // 等待一段時間,然后手動取消任務  time.Sleep(2 * time.Second)  cancel()  // 等待所有任務完成  wg.Wait()}

在上面例子中,創建了一個可以手動取消的 Context,并使用 sync.WaitGroup 等待所有任務完成。9x328資訊網——每日最新資訊28at.com

在 for 循環中,啟動了 5 個協程,每個協程會等待一段時間后輸出任務完成信息。9x328資訊網——每日最新資訊28at.com

在主函數中,程序等待了 2 秒后,手動調用 cancel 函數取消了任務,協程會接收到取消信號并退出。9x328資訊網——每日最新資訊28at.com

5.2 避免 Context 濫用

在使用 Context 時,要避免將 Context 放在結構體中。9x328資訊網——每日最新資訊28at.com

因為 Context 應該作為函數參數傳遞,而不應該被放在結構體中進行傳遞。9x328資訊網——每日最新資訊28at.com

Context 應該限定在程序的最小作用域,不要傳遞到不需要它的函數中。9x328資訊網——每日最新資訊28at.com

6. Context 的應用場景

6.1 HTTP 請求中的 Context 使用

package mainimport (  "fmt"  "net/http"  "time")func handler(w http.ResponseWriter, r *http.Request) {  ctx := r.Context()  select {  case <-time.After(2 * time.Second):    fmt.Fprintln(w, "Hello, World!")  case <-ctx.Done():    err := ctx.Err()    fmt.Println("Server:", err)    http.Error(w, err.Error(), http.StatusInternalServerError)  }}func main() {  http.HandleFunc("/", handler)  http.ListenAndServe(":8080", nil)}

在上面示例中,創建了一個 HTTP 請求處理函數 handler。9x328資訊網——每日最新資訊28at.com

在處理函數中,用 r.Context() 獲取到請求的 Context,并在其中執行一個耗時的任務。9x328資訊網——每日最新資訊28at.com

如果請求超時,ctx.Done() 會接收到取消信號,可以在其中處理請求超時的邏輯。9x328資訊網——每日最新資訊28at.com

6.2 數據庫操作中的 Context 使用

package mainimport (  "context"  "database/sql"  "fmt"  "time"  _ "github.com/go-sql-driver/mysql")func main() {  // 連接數據庫  db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/database")  if err != nil {    fmt.Println("數據庫連接失敗:", err)    return  }  defer db.Close()  // 創建一個Context,設置超時時間為5秒  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)  defer cancel()  // 在Context的超時時間內執行數據庫查詢  rows, err := db.QueryContext(ctx, "SELECT * FROM users")  if err != nil {    fmt.Println("數據庫查詢失敗:", err)    return  }  defer rows.Close()  // 處理查詢結果  for rows.Next() {    // 處理每一行數據  }}

在上面例子中,使用 database/sql 包進行數據庫查詢。創建了一個帶有 5 秒超時時間的 Context,并在其中執行數據庫查詢。9x328資訊網——每日最新資訊28at.com

如果查詢時間超過 5 秒,Context 會接收到取消信號,可以在其中執行處理查詢超時的邏輯。9x328資訊網——每日最新資訊28at.com

6.3 其他業務場景中的 Context 使用

在其他業務場景中,可使用 Context 實現更多復雜的任務協同。9x328資訊網——每日最新資訊28at.com

例如,使用 Context 在多個微服務之間進行數據傳遞和超時控制。9x328資訊網——每日最新資訊28at.com

以下是一個示例,演示了如何在微服務架構中使用 Context 進行跨服務的數據傳遞9x328資訊網——每日最新資訊28at.com

package mainimport (  "context"  "fmt"  "time")type Request struct {  ID int}type Response struct {  Message string}func microservice(ctx context.Context, reqCh chan Request, resCh chan Response) {  for {    select {    case <-ctx.Done():      fmt.Println("Microservice shutting down...")      return    case req := <-reqCh:      // 模擬處理請求的耗時操作      time.Sleep(2 * time.Second)      response := Response{Message: fmt.Sprintf("Processed request with ID %d", req.ID)}      resCh <- response    }  }}func main() {  // 創建根Context  rootContext := context.Background()  // 創建用于請求和響應的通道  reqCh := make(chan Request)  resCh := make(chan Response)  // 啟動微服務  go microservice(rootContext, reqCh, resCh)  // 創建帶有5秒超時時間的Context  ctx, cancel := context.WithTimeout(rootContext, 5*time.Second)  defer cancel()  // 發送請求到微服務  for i := 1; i <= 3; i++ {    req := Request{ID: i}    reqCh <- req    select {    case <-ctx.Done():      fmt.Println("Request timed out!")      return    case res := <-resCh:      fmt.Println(res.Message)    }  }}

在上面示例中,創建了一個簡單的微服務模擬,它接收來自 reqCh 通道的請求,并將處理結果發送到 resCh 通道。9x328資訊網——每日最新資訊28at.com

在主函數中,用帶有 5 秒超時時間的 Context 來確保請求不會無限期等待,同時也能夠處理超時的情況。9x328資訊網——每日最新資訊28at.com

7. 最佳實踐與注意事項

7.1 避免在函數庫中使用 Context

通常情況下,應該在函數的參數列表中顯式傳遞 Context,而不是將 Context 放在結構體中。9x328資訊網——每日最新資訊28at.com

這樣做可以使函數的行為更加明確,避免隱藏傳遞的 Context,提高代碼的可讀性和可維護性。9x328資訊網——每日最新資訊28at.com

7.2 避免在結構體中嵌入 Context

盡管可以將 Context 作為結構體的成員嵌入,但這樣的做法通常是不推薦的。9x328資訊網——每日最新資訊28at.com

因為 Context 應該是在函數調用的時候傳遞,而不是嵌入在結構體中。9x328資訊網——每日最新資訊28at.com

如果結構體的方法需要使用 Context,應該將 Context 作為參數傳遞給這些方法。9x328資訊網——每日最新資訊28at.com

7.3 注意 Context 的傳遞路徑

在實際應用中,要仔細考慮 Context 的傳遞路徑。9x328資訊網——每日最新資訊28at.com

若是在多個函數之間傳遞 Context,確保 Context 的傳遞路徑清晰明了,避免出現歧義和混亂。9x328資訊網——每日最新資訊28at.com

Context 的傳遞路徑應該盡量短,不要跨越過多的函數調用。9x328資訊網——每日最新資訊28at.com

總結

在 Go 語言中,Context 是一個強大的工具,用于處理請求的傳遞、控制和超時等。9x328資訊網——每日最新資訊28at.com

通過合理地使用 Context,可以編寫出更加穩定、高效的異步程序,提高系統的健壯性和可維護性。9x328資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-17162-0.htmlGo語言Context應用全攻略:異步編程利器

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Python編程必備:掌握列表遍歷的六種神級技巧!

下一篇: 一年經驗,你讓我精通微服務開發,過分嗎?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 伊春市| 龙江县| 绵竹市| 牡丹江市| 游戏| 林甸县| 霍山县| 孝昌县| 灌南县| 和顺县| 饶平县| 阿荣旗| 马龙县| 廊坊市| 信宜市| 邹平县| 黎平县| 石台县| 平果县| 杂多县| 定兴县| 克什克腾旗| 郓城县| 大竹县| 云南省| 兰考县| 左权县| 萨嘎县| 广南县| 佛冈县| 乌拉特前旗| 屏南县| 调兵山市| 深泽县| 云林县| 称多县| 宝兴县| 中超| 雷波县| 任丘市| 晴隆县|