欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go中的Context實(shí)現(xiàn)原理以及正確使用方式

 更新時(shí)間:2024年11月06日 08:47:04   作者:Chicken Run  
在 Go 語言中,Context 包是一種非常常用的工具,它被用來管理 goroutine 之間的通信和取消,本文將深入探討Context 包的基本原理,包括使用場景、原理和一些最佳實(shí)踐,感興趣的小伙伴跟著小編一起來看看吧

1. 基本原理

1.1 Context 包的介紹

在 Go 語言中,Context 包是用于傳遞請(qǐng)求范圍數(shù)據(jù)、取消信號(hào)和截止時(shí)間的機(jī)制。它通常被用來處理 goroutine 之間的通信和取消。Context 包是 Go 語言內(nèi)置的,它可以很方便地使用,而不需要額外的依賴。
Context 包是一個(gè)輕量級(jí)的工具,它提供了一個(gè)標(biāo)準(zhǔn)的接口,用于在 goroutine 之間傳遞請(qǐng)求范圍的數(shù)據(jù)、取消信號(hào)和截止時(shí)間。Context 包實(shí)現(xiàn)了一種類似于樹狀結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),其中每個(gè)節(jié)點(diǎn)都表示一個(gè)請(qǐng)求范圍。每個(gè)節(jié)點(diǎn)都有一個(gè)唯一的 key-value 對(duì),其中 key 是一個(gè) interface{} 類型的值,而 value 則是任何類型的值。Context 包還提供了一個(gè)可選的超時(shí)機(jī)制,用于在一定時(shí)間后自動(dòng)取消請(qǐng)求。

Context 包的核心是一個(gè) Context 接口,它定義了一些方法,用于獲取請(qǐng)求范圍數(shù)據(jù)、取消請(qǐng)求和處理超時(shí)。

 type Context interface {
     Deadline() (deadline time.Time, ok bool)
     Done() <-chan struct{}
     Err() error
     Value(key interface{}) interface{}
 }
  • Deadline() 方法返回截止時(shí)間和一個(gè)布爾值,指示截止時(shí)間是否已經(jīng)設(shè)置。
  • Done() 方法返回一個(gè)只讀的 channel,當(dāng)請(qǐng)求被取消或超時(shí)時(shí),該 channel 將被關(guān)閉。
  • Err() 方法返回一個(gè)錯(cuò)誤,指示為什么請(qǐng)求被取消。
  • Value() 方法返回與給定key相關(guān)聯(lián)的值,如果沒有值,則返回 nil。

Context 包還提供了兩個(gè)用于創(chuàng)建 Context 的函數(shù):WithContext 和 Background。Background 函數(shù)返回一個(gè)空的 Context,而 WithContext 函數(shù)則根據(jù)給定的父 Context 創(chuàng)建一個(gè)新的 Context。
Context 包的基本原理是通過在 goroutine 之間傳遞 Context 來實(shí)現(xiàn)請(qǐng)求范圍數(shù)據(jù)、取消信號(hào)和截止時(shí)間的管理。當(dāng)一個(gè) goroutine 創(chuàng)建了一個(gè)新的 goroutine 時(shí),它將 Context 作為參數(shù)傳遞給新的 goroutine。新的goroutine 可以使用這個(gè) Context 來訪問請(qǐng)求范圍數(shù)據(jù)、接收取消信號(hào)和處理超時(shí)。

1.2 Context 的創(chuàng)建

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

1.2.1 WithCancel

WithCancel 函數(shù)可以用于創(chuàng)建一個(gè) Context 對(duì)象,并返回一個(gè)可取消的上下文和一個(gè)取消函數(shù)。當(dāng)調(diào)用取消函數(shù)時(shí),會(huì)通知所有的 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。

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

下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithCancel 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)可取消的上下文和一個(gè)取消函數(shù) cancel。接下來,我們?cè)谝粋€(gè) goroutine 中使用 select 語句監(jiān)聽 Context 對(duì)象的 Done 方法和 time.After 函數(shù)的返回值,如果 Done 方法返回一個(gè)非 nil 的 error,則說明 Context 已經(jīng)被取消,否則說明 time.After 函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用 cancel 函數(shù)來通知 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。最后,我們使用 time.Sleep 函數(shù)讓程序等待一段時(shí)間,以便觀察 Context 的執(zhí)行情況。

1.2.2 WithDeadline

WithDeadline 函數(shù)可以用于創(chuàng)建一個(gè) Context 對(duì)象,并返回一個(gè)截止時(shí)間和一個(gè)取消函數(shù)。當(dāng)超過截止時(shí)間時(shí),會(huì)自動(dòng)通知所有的 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。

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

下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithDeadline 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)截止時(shí)間和一個(gè)取消函數(shù) cancel。接下來,我們?cè)谝粋€(gè) goroutine 中使用 select 語句監(jiān)聽 Context 對(duì)象的 Done 方法和 time.After 函數(shù)的返回值,如果 Done 方法返回一個(gè)非 nil 的 error,則說明 Context 已經(jīng)被取消,否則說明 time.After 函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用 cancel 函數(shù)來通知 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。最后,我們使用 time.Sleep 函數(shù)讓程序等待一段時(shí)間,以便觀察 Context 的執(zhí)行情況。

1.2.3 WithTimeout

WithTimeout 函數(shù)可以用于創(chuàng)建一個(gè) Context 對(duì)象,并返回一個(gè)超時(shí)時(shí)間和一個(gè)取消函數(shù)。當(dāng)超過超時(shí)時(shí)間時(shí),會(huì)自動(dòng)通知所有的 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。

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

下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithTimeout 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)超時(shí)時(shí)間和一個(gè)取消函數(shù) cancel。接下來,我們?cè)谝粋€(gè) goroutine 中使用 select 語句監(jiān)聽 Context 對(duì)象的 Done 方法和 time.After 函數(shù)的返回值,如果 Done 方法返回一個(gè)非 nil 的 error,則說明 Context 已經(jīng)被取消,否則說明 time.After 函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用 cancel 函數(shù)來通知 Context 對(duì)象和其子 Context 對(duì)象,使它們都取消執(zhí)行。最后,我們使用 time.Sleep 函數(shù)讓程序等待一段時(shí)間,以便觀察 Context 的執(zhí)行情況。

1.2.4 WithValue

WithValue 函數(shù)可以用于創(chuàng)建一個(gè) Context 對(duì)象,并返回一個(gè)包含指定值的 Context 對(duì)象。這個(gè)值可以是任意類型的數(shù)據(jù),可以是基本類型、結(jié)構(gòu)體或者指針等。需要注意的是,這個(gè)值只在當(dāng)前 Context 對(duì)象及其子 Context 對(duì)象中有效,對(duì)于其他 Context 對(duì)象來說是不可見的。

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

下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithValue 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)包含指定值的 Context 對(duì)象。接下來,我們?cè)谝粋€(gè) goroutine 中使用 ctx.Value 函數(shù)獲取 Context 對(duì)象中的值,并判斷其類型是否為字符串類型。如果是,則輸出其值,否則輸出 “user is not found”。在主函數(shù)中,我們使用select語句使程序一直運(yùn)行,以便觀察 Context 的執(zhí)行情況。

2. Context 的使用場景

2.1 并發(fā)控制

一個(gè)很典型的使用場景是,當(dāng)我們需要同時(shí)啟動(dòng)多個(gè) goroutine 進(jìn)行任務(wù)處理時(shí),我們可以使用 Context 來控制這些 goroutine 的執(zhí)行。在每個(gè) goroutine 中,我們都可以檢測 Context 對(duì)象是否被取消,如果是,則退出 goroutine 的執(zhí)行,否則繼續(xù)執(zhí)行。

下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithCancel 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)取消函數(shù) cancel。接下來,我們使用 sync.WaitGroup 來等待所有的 goroutine 執(zhí)行完成。在主函數(shù)中,我們啟動(dòng)了三個(gè) goroutine 來執(zhí)行任務(wù),同時(shí)使用 cancel 函數(shù)來通知這些 goroutine 取消執(zhí)行。最后,我們使用Wait方法等待所有的 goroutine 執(zhí)行完成。

2.2 超時(shí)控制

另一個(gè)典型的使用場景是,當(dāng)我們需要對(duì)一個(gè)操作設(shè)置一個(gè)超時(shí)時(shí)間時(shí),我們可以使用 Context 來控制這個(gè)操作的執(zhí)行時(shí)間。在操作執(zhí)行超時(shí)時(shí),我們可以通知 Context 對(duì)象和其子 Context 對(duì)象取消執(zhí)行。
下面是一個(gè)示例代碼:

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() 函數(shù)創(chuàng)建一個(gè)根 Context 對(duì)象 parent,然后使用 WithTimeout 函數(shù)創(chuàng)建一個(gè)子 Context 對(duì)象 ctx,并返回一個(gè)取消函數(shù) cancel。在 work 函數(shù)中,我們啟動(dòng)一個(gè)無限循環(huán),不斷輸出 “work”。同時(shí),我們使用 select 語句來等待 Context 對(duì)象被取消。在主函數(shù)中,我們使用 defer 語句調(diào)用 cancel 函數(shù),以確保 Context 對(duì)象被取消。由于我們?cè)?WithTimeout 函數(shù)中設(shè)置了一個(gè) 5 秒的超時(shí)時(shí)間,因此當(dāng)程序運(yùn)行超過 5 秒時(shí),work 函數(shù)就會(huì)停止執(zhí)行。

2.3 數(shù)據(jù)庫連接

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

下面是一個(gè)示例代碼:

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 函數(shù)打開一個(gè) MySQL 數(shù)據(jù)庫的連接,并返回一個(gè) DB 對(duì)象 db。接下來,我們使用 WithTimeout 函數(shù)創(chuàng)建一個(gè) Context 對(duì)象 ctx,并設(shè)置一個(gè)超時(shí)時(shí)間為 5 秒。同時(shí),我們創(chuàng)建一個(gè)容量為 maxConn 的 channel 對(duì)象 connCh,用于存儲(chǔ)數(shù)據(jù)庫連接。在g oroutine 中,我們使用 select 語句等待 Context 對(duì)象被取消。在每次循環(huán)中,我們檢查連接池中連接的數(shù)量是否超過了閾值,如果沒有,則使用 db.Conn 函數(shù)從連接池中獲取一個(gè)新的連接,并將其存儲(chǔ)到 connCh 中。最后,我們使用 sync.WaitGroup 等待所有的 goroutine 執(zhí)行完成。

2.4 HTTP 請(qǐng)求

在使用 HTTP 請(qǐng)求時(shí),我們通常需要設(shè)置一個(gè)超時(shí)時(shí)間,以確保請(qǐng)求能夠在規(guī)定的時(shí)間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用 Context 來控制HTTP請(qǐng)求的執(zhí)行時(shí)間。

下面是一個(gè)示例代碼:

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 創(chuàng)建一個(gè) HTTP 客戶端對(duì)象 client。接下來,我們使用 WithTimeout 函數(shù)創(chuàng)建一個(gè) Context 對(duì)象 ctx,并設(shè)置一個(gè)超時(shí)時(shí)間為 5 秒。同時(shí),我們使用 http.NewRequestWithContext 函數(shù)創(chuàng)建一個(gè) HTTP 請(qǐng)求對(duì)象 req,并將 Context 對(duì)象 ctx 作為參數(shù)傳遞給該函數(shù)。在 Do 函數(shù)中,我們會(huì)自動(dòng)將 Context 對(duì)象 ctx 傳遞給 HTTP 請(qǐng)求,并在超時(shí)時(shí)間到達(dá)后自動(dòng)取消該請(qǐng)求。

2.5 gRPC 請(qǐng)求

在使用 gRPC 請(qǐng)求時(shí),我們通常需要設(shè)置一個(gè)超時(shí)時(shí)間,以確保請(qǐng)求能夠在規(guī)定的時(shí)間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用 Context 來控制 gRPC 請(qǐng)求的執(zhí)行時(shí)間。

下面是一個(gè)示例代碼:

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 函數(shù)創(chuàng)建一個(gè) gRPC 客戶端連接對(duì)象 conn。接下來,我們使用 pb.NewGreeterClient 函數(shù)創(chuàng)建一個(gè) GreeterClient 對(duì)象 c。然后,我們使用 WithTimeout 函數(shù)創(chuàng)建一個(gè) Context 對(duì)象 ctx,并設(shè)置一個(gè)超時(shí)時(shí)間為 5 秒。最后,我們使用 GreeterClient 對(duì)象 c 的 SayHello 函數(shù)發(fā)送一個(gè) gRPC 請(qǐng)求,并將 Context 對(duì)象 ctx 作為參數(shù)傳遞給該函數(shù)。在 SayHello 函數(shù)中,我們會(huì)自動(dòng)將 Context 對(duì)象 ctx 傳遞給 gRPC 請(qǐng)求,并在超時(shí)時(shí)間到達(dá)后自動(dòng)取消該請(qǐng)求。

Go Context 到底放第一個(gè)參數(shù)傳,還是放結(jié)構(gòu)體里?

作為函數(shù)的第一個(gè)參數(shù)

優(yōu)點(diǎn):

  1. 明確性:將context作為第一個(gè)參數(shù),清晰地表明了函數(shù)執(zhí)行的上下文依賴,增強(qiáng)了代碼的可讀性和意圖表達(dá)。這種方式符合Go的設(shè)計(jì)哲學(xué),即顯式優(yōu)于隱式。

  2. 易于測試:測試時(shí)可以輕松創(chuàng)建并傳遞一個(gè)自定義的context.Context實(shí)例,便于控制測試中的超時(shí)和取消邏輯,無需修改函數(shù)簽名或結(jié)構(gòu)體定義。

  3. 標(biāo)準(zhǔn)一致性:Go的標(biāo)準(zhǔn)庫廣泛采用了這種模式,比如net/http包中的ServeHTTP方法。遵循這一標(biāo)準(zhǔn)使得代碼風(fēng)格統(tǒng)一,便于其他開發(fā)者理解和維護(hù)。

缺點(diǎn):

  1. 參數(shù)列表增長:對(duì)于參數(shù)較多的函數(shù),額外增加一個(gè)context.Context可能會(huì)讓函數(shù)簽名顯得冗長,特別是當(dāng)多個(gè)函數(shù)嵌套調(diào)用時(shí),每一層都需要傳遞context。

  2. 侵入性:雖然增加了靈活性,但也意味著每一個(gè)需要考慮取消或超時(shí)邏輯的函數(shù)都需要調(diào)整,對(duì)于既有代碼庫的改造成本較高。

嵌入到結(jié)構(gòu)體中

優(yōu)點(diǎn):

  1. 減少函數(shù)簽名復(fù)雜度:將context.Context作為一個(gè)字段嵌入到結(jié)構(gòu)體中,可以減少函數(shù)參數(shù)的數(shù)量,使函數(shù)簽名更加簡潔。

  2. 封裝性:對(duì)于內(nèi)部邏輯復(fù)雜的服務(wù),將context隱藏在結(jié)構(gòu)體內(nèi)部,可以對(duì)外提供更加抽象和友好的接口,提高代碼的封裝性。

缺點(diǎn):

  1. 測試復(fù)雜度增加:如果結(jié)構(gòu)體中的context字段不是公開的,測試時(shí)可能需要通過構(gòu)造特定的結(jié)構(gòu)體實(shí)例來傳遞特定的上下文信息,這可能使得測試代碼變得復(fù)雜。

  2. 靈活性降低:一旦context作為結(jié)構(gòu)體的一部分,函數(shù)調(diào)用時(shí)就失去了直接控制context的能力,比如無法在運(yùn)行時(shí)輕易改變超時(shí)時(shí)間或取消策略。

實(shí)踐建議

  • 常規(guī)操作:對(duì)于大多數(shù)情況,遵循Go標(biāo)準(zhǔn)庫的推薦,將context作為函數(shù)的第一個(gè)參數(shù)傳遞是最佳選擇。這樣做既體現(xiàn)了Go的簡潔和明了,也便于維護(hù)和測試。

  • 高度封裝的服務(wù):在設(shè)計(jì)高度封裝的內(nèi)部服務(wù)或復(fù)雜的API時(shí),可以考慮將context嵌入到結(jié)構(gòu)體中,尤其是當(dāng)需要在整個(gè)服務(wù)生命周期內(nèi)管理上下文時(shí)。但需權(quán)衡好封裝性和測試便利性之間的關(guān)系。

  • 混合使用:在某些場景下,你可能會(huì)發(fā)現(xiàn)結(jié)合兩者使用的效果更好。例如,在服務(wù)初始化階段,將context作為結(jié)構(gòu)體字段管理,而在服務(wù)的具體操作函數(shù)中,依然將context作為第一個(gè)參數(shù)傳遞,以保持操作的靈活性。

總之,選擇將context放在哪里,應(yīng)基于項(xiàng)目的具體需求、代碼的可讀性和維護(hù)性綜合考量。無論哪種方式,關(guān)鍵在于理解并充分利用context機(jī)制,以提升程序的健壯性和可維護(hù)性。

以上就是Go中的Context實(shí)現(xiàn)原理以及正確使用方式的詳細(xì)內(nèi)容,更多關(guān)于Go Context實(shí)現(xiàn)原理及使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論