【Go - context 速览,场景与用法】
创始人
2024-12-17 06:36:20
0

作用

context字面意思上下文,用于关联管理上下文,具体有如下几个作用

  1. 取消信号传递:可以用来传递取消信号,让一个正在执行的函数知道它应该提前终止。
  2. 超时控制:可以设定一个超时时间,自动取消超过执行时间的操作。
  3. 截止时间:与超时类似,但是是设定一个绝对时间点,而不是时间段。
  4. 值传递:可以安全地在请求的上下文中传递数据,避免了使用全局变量或者参数列表不断增长。

由上述看出,context有个重要用途,控制取消

场景与用法

示例1:HTTP 请求处理

在处理 HTTP 请求时,可以为每个请求创建一个 context,用于控制请求处理的整个生命周期。如果请求被取消或超时,依赖该 context 的操作也会被取消。

代码示例

package main  import ( 	"context" 	"fmt" 	"math/rand" 	"net/http" 	"time" )  func randomSleepAtMost2s() { 	rand.Seed(time.Now().UnixNano()) // 初始化随机数种子 	// 生成 0 到 2000 之间的随机整数(毫秒) 	randomMillis := rand.Intn(2000) 	// 转换为 time.Duration 类型,并乘以 time.Millisecond 	sleepDuration := time.Duration(randomMillis) * time.Millisecond 	// 随机睡眠 	fmt.Println("sleeping for", sleepDuration) 	time.Sleep(sleepDuration) }  func handler(w http.ResponseWriter, r *http.Request) { 	// 超时时间1s 	ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second) 	defer cancel()  	// 创建一个模拟正常处理完成的通道 	done := make(chan struct{})  	// 模拟异步处理逻辑 	go func() { 		// 模拟耗时操作 		// - 当随机睡眠超过1s时,会触发 ctx.Done(),取消请求 		// - 当随机睡眠不超过1s时,则会正常处理请求 		randomSleepAtMost2s() 		fmt.Println("request processed") 		close(done) // 处理完成,关闭通道 	}()  	// 模拟耗时操作 	select { 	case <-done: 		w.WriteHeader(http.StatusOK) 		w.Write([]byte("request processed successfully")) 	case <-ctx.Done(): 		fmt.Println("request cancelled") 		http.Error(w, "request cancelled", http.StatusRequestTimeout) 		return 	} }  func main() { 	http.HandleFunc("/", handler) 	http.ListenAndServe(":8080", nil) }  

示例2 :数据库操作

数据库查询或操作可以接受一个 context 参数,允许查询在超时或被取消时立即停止,避免无谓的数据库资源占用。

代码示例

package main  import ( 	"context" 	"database/sql" 	"fmt" 	"time"  	_ "github.com/lib/pq" // 假设使用 PostgreSQL )  func queryWithTimeout(ctx context.Context, db *sql.DB, query string) (*sql.Rows, error) { 	// 设置1s的超时时间 	ctx, cancel := context.WithTimeout(ctx, 1*time.Second) 	defer cancel()  	return db.QueryContext(ctx, query) }  func main() { 	// 连接数据库(示例) 	db, err := sql.Open("postgres", "your_connection_string") 	if err != nil { 		panic(err) 	} 	defer db.Close()  	ctx := context.Background() 	_, err = queryWithTimeout(ctx, db, "SELECT * FROM your_table") 	if err != nil { 		fmt.Println("Query failed:", err) 	} }  

示例3:取消协程

在启动多个 goroutine 进行并发操作时,可以通过 context 控制这些 goroutine 的生命周期,确保它们能够在必要时被正确取消。

代码示例

package main  import ( 	"context" 	"fmt" 	"time" )  func operation(ctx context.Context, id int) { 	select { 	case <-time.After(2 * time.Second): 		fmt.Printf("Operation %d completed\n", id) 	case <-ctx.Done(): 		fmt.Printf("Operation %d cancelled\n", id) 	} }  func main() { 	ctx, cancel := context.WithCancel(context.Background())  	for i := 0; i < 5; i++ { 		go operation(ctx, i) 	}  	time.Sleep(1 * time.Second) 	cancel()                    // 取消所有协程操作 	time.Sleep(3 * time.Second) // 等待足够的时间以打印完日志,观察效果 }  

示例4:跨服务调用

在微服务架构中,一个服务调用另一个服务时,可以通过 context 传递关于原始请求的信息,如请求ID,以便进行链路追踪。

代码示例

package main  import ( 	"context" 	"fmt" 	"net/http" 	"time" )  func callService(ctx context.Context, url string) { 	req, _ := http.NewRequest("GET", url, nil) 	req = req.WithContext(ctx)  	client := &http.Client{} 	resp, err := client.Do(req) 	if err != nil { 		fmt.Println("Request failed:", err) 		return 	} 	defer resp.Body.Close()  	fmt.Println("Response status:", resp.Status) }  func main() { 	ctx := context.Background() 	ctx = context.WithValue(ctx, "RequestID", "abc123") 	ctx, cancel := context.WithTimeout(ctx, 1*time.Second) 	defer cancel()  	callService(ctx, "http://example.com") } 

结语

通过这些场景和用法,可以看出 context 在 Go 中的重要性,特别是在需要控制管理请求生命周期时(控制取消)。

相关内容

热门资讯

分享给玩家!潮汕闲来麻将app... 分享给玩家!潮汕闲来麻将app有挂吗(透视辅助)透视脚本辅助插件(2021已更新)(哔哩哔哩)1、玩...
推荐十款!白金岛跑得快开挂安全... 推荐十款!白金岛跑得快开挂安全吗(切实真的有挂)详细透视教程;1、白金岛跑得快开挂安全吗机器人多个强...
科技介绍!决战十三水输赢规律(... 科技介绍!决战十三水输赢规律(透视)透视脚本辅助app(2021已更新)(哔哩哔哩)决战十三水输赢规...
重大来袭!财神13张有外挂吗(... 重大来袭!财神13张有外挂吗(原来是真的有挂)详细透视辅助教程1、财神13张有外挂吗机器人多个强度级...
最新技巧!!中至乐平麻将小程序... 最新技巧!!中至乐平麻将小程序(辅助挂)透视脚本辅助软件(2023已更新)(哔哩哔哩)1、下载好中至...
总算了解!桂麻圈辅助器(其实是... 总算了解!桂麻圈辅助器(其实是真的有挂)详细辅助挂教程1、每一步都需要思考,不同水平的挑战会更加具有...
热点推荐!!天天福建十三张苹果... 热点推荐!!天天福建十三张苹果版怎么调胜率(辅助挂)透视辅助app(2022已更新)(哔哩哔哩)1、...
揭秘一下!天涯麻将有脚本吗(透... 揭秘一下!天涯麻将有脚本吗(透视辅助)外挂透明挂辅助app(2020已更新)(哔哩哔哩)天涯麻将有脚...
最新技巧!琼雀海南骨牌有挂吗(... 最新技巧!琼雀海南骨牌有挂吗(其实真的是有挂)详细辅助教程1)琼雀海南骨牌有挂吗辅助挂:进一步探索琼...
科普分享!拱趴大菠萝有外挂吗(... 科普分享!拱趴大菠萝有外挂吗(辅助挂)透明挂透视辅助工具(2021已更新)(哔哩哔哩)1、该软件可以...