亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang?Context包怎么創建使用

發布時間:2023-05-04 17:53:24 來源:億速云 閱讀:191 作者:iii 欄目:開發技術

這篇文章主要介紹“Golang Context包怎么創建使用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Golang Context包怎么創建使用”文章能幫助大家解決問題。

    1. 基本原理

    1.1 Context 包的介紹

    在 Go 語言中,Context 包是用于傳遞請求范圍數據、取消信號和截止時間的機制。它通常被用來處理 goroutine 之間的通信和取消。Context 包是 Go 語言內置的,它可以很方便地使用,而不需要額外的依賴。

    Context 包是一個輕量級的工具,它提供了一個標準的接口,用于在 goroutine 之間傳遞請求范圍的數據、取消信號和截止時間。Context 包實現了一種類似于樹狀結構的數據結構,其中每個節點都表示一個請求范圍。每個節點都有一個唯一的 key-value 對,其中 key 是一個 interface{} 類型的值,而 value 則是任何類型的值。Context 包還提供了一個可選的超時機制,用于在一定時間后自動取消請求。

    Context 包的核心是一個 Context 接口,它定義了一些方法,用于獲取請求范圍數據、取消請求和處理超時。

     type Context interface {
         Deadline() (deadline time.Time, ok bool)
         Done() <-chan struct{}
         Err() error
         Value(key interface{}) interface{}
     }
    • Deadline() 方法返回截止時間和一個布爾值,指示截止時間是否已經設置。

    • Done() 方法返回一個只讀的 channel,當請求被取消或超時時,該 channel 將被關閉。

    • Err() 方法返回一個錯誤,指示為什么請求被取消。

    • Value() 方法返回與給定key相關聯的值,如果沒有值,則返回 nil。

    Context 包還提供了兩個用于創建 Context 的函數:WithContext 和 Background。Background 函數返回一個空的 Context,而 WithContext 函數則根據給定的父 Context 創建一個新的 Context。

    Context 包的基本原理是通過在 goroutine 之間傳遞 Context 來實現請求范圍數據、取消信號和截止時間的管理。當一個 goroutine 創建了一個新的 goroutine 時,它將 Context 作為參數傳遞給新的 goroutine。新的goroutine 可以使用這個 Context 來訪問請求范圍數據、接收取消信號和處理超時。

    1.2 Context 的創建

    在 Golang 中,Context 可以通過 WithCancel、WithDeadline、WithTimeout 和 WithValue 等函數來創建。下面分別介紹這些函數的用法和注意事項。

    1.2.1 WithCancel

    WithCancel 函數可以用于創建一個 Context 對象,并返回一個可取消的上下文和一個取消函數。當調用取消函數時,會通知所有的 Context 對象和其子 Context 對象,使它們都取消執行。

     func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "time"
     )
     
     func main() {
         parent := context.Background()
         ctx, cancel := context.WithCancel(parent)
         go func() {
             select {
             case <-ctx.Done():
                 fmt.Println(ctx.Err())
                 return
             case <-time.After(5 * time.Second):
                 fmt.Println("work done")
             }
         }()
         time.Sleep(10 * time.Second)
         cancel()
         time.Sleep(1 * time.Second)
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithCancel 函數創建一個子 Context 對象 ctx,并返回一個可取消的上下文和一個取消函數 cancel。接下來,我們在一個 goroutine 中使用 select 語句監聽 Context 對象的 Done 方法和 time.After 函數的返回值,如果 Done 方法返回一個非 nil 的 error,則說明 Context 已經被取消,否則說明 time.After 函數已經超時。在主函數中,我們調用 cancel 函數來通知 Context 對象和其子 Context 對象,使它們都取消執行。最后,我們使用 time.Sleep 函數讓程序等待一段時間,以便觀察 Context 的執行情況。

    1.2.2 WithDeadline

    WithDeadline 函數可以用于創建一個 Context 對象,并返回一個截止時間和一個取消函數。當超過截止時間時,會自動通知所有的 Context 對象和其子 Context 對象,使它們都取消執行。

     func WithDeadline(parent Context, deadline time.Time) (ctx Context, cancel CancelFunc)

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "time"
     )
     
     func main() {
         parent := context.Background()
         ctx, cancel := context.WithDeadline(parent, time.Now().Add(5*time.Second))
         go func() {
             select {
             case <-ctx.Done():
                 fmt.Println(ctx.Err())
                 return
             case <-time.After(10 * time.Second):
                 fmt.Println("work done")
             }
         }()
         time.Sleep(20 * time.Second)
         cancel()
         time.Sleep(1 * time.Second)
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithDeadline 函數創建一個子 Context 對象 ctx,并返回一個截止時間和一個取消函數 cancel。接下來,我們在一個 goroutine 中使用 select 語句監聽 Context 對象的 Done 方法和 time.After 函數的返回值,如果 Done 方法返回一個非 nil 的 error,則說明 Context 已經被取消,否則說明 time.After 函數已經超時。在主函數中,我們調用 cancel 函數來通知 Context 對象和其子 Context 對象,使它們都取消執行。最后,我們使用 time.Sleep 函數讓程序等待一段時間,以便觀察 Context 的執行情況。

    1.2.3 WithTimeout

    WithTimeout 函數可以用于創建一個 Context 對象,并返回一個超時時間和一個取消函數。當超過超時時間時,會自動通知所有的 Context 對象和其子 Context 對象,使它們都取消執行。

     func WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancel CancelFunc)

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "time"
     )
     
     func main() {
         parent := context.Background()
         ctx, cancel := context.WithTimeout(parent, 5*time.Second)
         go func() {
             select {
             case <-ctx.Done():
                 fmt.Println(ctx.Err())
                 return
             case <-time.After(10 * time.Second):
                 fmt.Println("work done")
             }
         }()
         time.Sleep(20 * time.Second)
         cancel()
         time.Sleep(1 * time.Second)
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithTimeout 函數創建一個子 Context 對象 ctx,并返回一個超時時間和一個取消函數 cancel。接下來,我們在一個 goroutine 中使用 select 語句監聽 Context 對象的 Done 方法和 time.After 函數的返回值,如果 Done 方法返回一個非 nil 的 error,則說明 Context 已經被取消,否則說明 time.After 函數已經超時。在主函數中,我們調用 cancel 函數來通知 Context 對象和其子 Context 對象,使它們都取消執行。最后,我們使用 time.Sleep 函數讓程序等待一段時間,以便觀察 Context 的執行情況。

    1.2.4 WithValue

    WithValue 函數可以用于創建一個 Context 對象,并返回一個包含指定值的 Context 對象。這個值可以是任意類型的數據,可以是基本類型、結構體或者指針等。需要注意的是,這個值只在當前 Context 對象及其子 Context 對象中有效,對于其他 Context 對象來說是不可見的。

     func WithValue(parent Context, key interface{}, val interface{}) Context

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
     )
     
     type userKey struct{}
     
     func main() {
         parent := context.Background()
         ctx := context.WithValue(parent, userKey{}, "admin")
         go func() {
             if user, ok := ctx.Value(userKey{}).(string); ok {
                 fmt.Printf("user is %s\n", user)
             } else {
                 fmt.Println("user is not found")
             }
         }()
         select {}
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithValue 函數創建一個子 Context 對象 ctx,并返回一個包含指定值的 Context 對象。接下來,我們在一個 goroutine 中使用 ctx.Value 函數獲取 Context 對象中的值,并判斷其類型是否為字符串類型。如果是,則輸出其值,否則輸出 “user is not found”。在主函數中,我們使用select語句使程序一直運行,以便觀察 Context 的執行情況。

    2. Context 的使用場景

    2.1 并發控制

    一個很典型的使用場景是,當我們需要同時啟動多個 goroutine 進行任務處理時,我們可以使用 Context 來控制這些 goroutine 的執行。在每個 goroutine 中,我們都可以檢測 Context 對象是否被取消,如果是,則退出 goroutine 的執行,否則繼續執行。

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "sync"
     )
     
     func worker(ctx context.Context, wg *sync.WaitGroup) {
         defer wg.Done()
         for {
             select {
             default:
                 fmt.Println("work")
             case <-ctx.Done():
                 return
             }
         }
     }
     
     func main() {
         parent := context.Background()
         ctx, cancel := context.WithCancel(parent)
         var wg sync.WaitGroup
         for i := 0; i < 3; i++ {
             wg.Add(1)
             go worker(ctx, &wg)
         }
         cancel()
         wg.Wait()
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithCancel 函數創建一個子 Context 對象 ctx,并返回一個取消函數 cancel。接下來,我們使用 sync.WaitGroup 來等待所有的 goroutine 執行完成。在主函數中,我們啟動了三個 goroutine 來執行任務,同時使用 cancel 函數來通知這些 goroutine 取消執行。最后,我們使用Wait方法等待所有的 goroutine 執行完成。

    2.2 超時控制

    另一個典型的使用場景是,當我們需要對一個操作設置一個超時時間時,我們可以使用 Context 來控制這個操作的執行時間。在操作執行超時時,我們可以通知 Context 對象和其子 Context 對象取消執行。

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "time"
     )
     
     func work(ctx context.Context) {
         for {
             select {
             default:
                 fmt.Println("work")
             case <-ctx.Done():
                 fmt.Println("work done")
                 return
             }
         }
     }
         
     func main() {
         parent := context.Background()
         ctx, cancel := context.WithTimeout(parent, time.Second*5)
         defer cancel()
         work(ctx)
     }

    在上面的代碼中,我們首先使用 context.Background() 函數創建一個根 Context 對象 parent,然后使用 WithTimeout 函數創建一個子 Context 對象 ctx,并返回一個取消函數 cancel。在 work 函數中,我們啟動一個無限循環,不斷輸出 “work”。同時,我們使用 select 語句來等待 Context 對象被取消。在主函數中,我們使用 defer 語句調用 cancel 函數,以確保 Context 對象被取消。由于我們在 WithTimeout 函數中設置了一個 5 秒的超時時間,因此當程序運行超過 5 秒時,work 函數就會停止執行。

    2.3 數據庫連接

    在使用數據庫連接時,我們通常需要保證連接池中的連接數量不會超過一定的閾值。如果連接池中的連接數量超過了閾值,則需要等待連接釋放后再進行操作。在這種情況下,我們可以使用 Context 來控制連接的生命周期。

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "database/sql"
         "fmt"
         "sync"
         "time"
     
         _ "github.com/go-sql-driver/mysql"
     )
     
     const maxConn = 5
     
     func main() {
         db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
         if err != nil {
             panic(err)
         }
         defer db.Close()
     
         ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
         defer cancel()
     
         connCh := make(chan *sql.Conn, maxConn)
         var wg sync.WaitGroup
         for i := 0; i < maxConn; i++ {
             wg.Add(1)
             go func() {
                 defer wg.Done()
                 for {
                     select {
                     case <-ctx.Done():
                         return
                     default:
                         if len(connCh) < maxConn {
                             conn, err := db.Conn(ctx)
                             if err != nil {
                                 fmt.Println(err)
                                 return
                             }
                             connCh <- conn
                         }
                     }
                 }
             }()
         }
         wg.Wait()
     }

    在上面的代碼中,我們首先使用 sql.Open 函數打開一個 MySQL 數據庫的連接,并返回一個 DB 對象 db。接下來,我們使用 WithTimeout 函數創建一個 Context 對象 ctx,并設置一個超時時間為 5 秒。同時,我們創建一個容量為 maxConn 的 channel 對象 connCh,用于存儲數據庫連接。在g oroutine 中,我們使用 select 語句等待 Context 對象被取消。在每次循環中,我們檢查連接池中連接的數量是否超過了閾值,如果沒有,則使用 db.Conn 函數從連接池中獲取一個新的連接,并將其存儲到 connCh 中。最后,我們使用 sync.WaitGroup 等待所有的 goroutine 執行完成。

    2.4 HTTP 請求

    在使用 HTTP 請求時,我們通常需要設置一個超時時間,以確保請求能夠在規定的時間內得到響應。在這種情況下,我們可以使用 Context 來控制HTTP請求的執行時間。

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "io/ioutil"
         "net/http"
         "time"
     )
     
     func main() {
         client := http.DefaultClient
         ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
         defer cancel()
         req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://www.example.com", nil)
         if err != nil {
             fmt.Println(err)
             return
         }
     
         resp, err := client.Do(req)
         if err != nil {
             fmt.Println(err)
             return
         }
         defer resp.Body.Close()
     
         body, err := ioutil.ReadAll(resp.Body)
         if err != nil {
             fmt.Println(err)
             return
         }
     
         fmt.Println(string(body))
     }

    在上面的代碼中,我們首先使用 http.DefaultClient 創建一個 HTTP 客戶端對象 client。接下來,我們使用 WithTimeout 函數創建一個 Context 對象 ctx,并設置一個超時時間為 5 秒。同時,我們使用 http.NewRequestWithContext 函數創建一個 HTTP 請求對象 req,并將 Context 對象 ctx 作為參數傳遞給該函數。在 Do 函數中,我們會自動將 Context 對象 ctx 傳遞給 HTTP 請求,并在超時時間到達后自動取消該請求。

    2.5 gRPC 請求

    在使用 gRPC 請求時,我們通常需要設置一個超時時間,以確保請求能夠在規定的時間內得到響應。在這種情況下,我們可以使用 Context 來控制 gRPC 請求的執行時間。

    下面是一個示例代碼:

     package main
     
     import (
         "context"
         "fmt"
         "log"
         "time"
     
         pb "github.com/example/helloworld"
         "google.golang.org/grpc"
     )
     
     const (
         address     = "localhost:50051"
         defaultName = "world"
     )
     
     func main() {
         conn, err := grpc.Dial(address, grpc.WithInsecure())
         if err != nil {
             log.Fatalf("did not connect: %v", err)
         }
         defer conn.Close()
     
         c := pb.NewGreeterClient(conn)
     
         ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
         defer cancel()
     
         r, err := c.SayHello(ctx, &pb.HelloRequest{Name: defaultName})
         if err != nil {
             log.Fatalf("could not greet: %v", err)
         }
         log.Printf("Greeting: %s", r.GetMessage())
     }

    在上面的代碼中,我們首先使用 grpc.Dial 函數創建一個 gRPC 客戶端連接對象 conn。接下來,我們使用 pb.NewGreeterClient 函數創建一個 GreeterClient 對象 c。然后,我們使用 WithTimeout 函數創建一個 Context 對象 ctx,并設置一個超時時間為 5 秒。最后,我們使用 GreeterClient 對象 c 的 SayHello 函數發送一個 gRPC 請求,并將 Context 對象 ctx 作為參數傳遞給該函數。在 SayHello 函數中,我們會自動將 Context 對象 ctx 傳遞給 gRPC 請求,并在超時時間到達后自動取消該請求。

    關于“Golang Context包怎么創建使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    民乐县| 辽阳县| 彰武县| 丰顺县| 盈江县| 虹口区| 灵石县| 晋中市| 乌兰浩特市| 虎林市| 兴和县| 财经| 株洲市| 弥渡县| 渑池县| 西贡区| 洛阳市| 民丰县| 株洲市| 马公市| 绥化市| 东平县| 尤溪县| 抚宁县| 教育| 工布江达县| 昌江| 儋州市| 齐河县| 新疆| 吴堡县| 古交市| 兰西县| 南皮县| 海兴县| 平乡县| 鹤峰县| 虹口区| 阳春市| 灵石县| 都昌县|