Skip to content

context基本使用示例

约 622 字大约 2 分钟

2025-05-17

测试代码

package main

import (
	"context"
	"fmt"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/handlers"
	_ "github.com/mkevac/debugcharts"
	"log"
	"net/http"
	"time"
)

func startGoroutine(ctx context.Context, cnt int) {
	if cnt <= 0 {
		cnt = 100
	}
	for i := 0; i < 100; i++ {
		go func(cancelCtx context.Context, idx int) {
			for {
				hasFinish := false
				select {
				case <-cancelCtx.Done():
					hasFinish = true
					fmt.Println("goroutine ", idx, " is finished  ", time.Now().Format(time.DateTime))
					break
				default:
					time.Sleep(time.Second)
					fmt.Println("goroutine ", idx, " is running")
				}
				if hasFinish {
					break
				}
			}
		}(ctx, i)
	}
}
func main() {
	r := gin.Default()
	pprof.Register(r)
	// 测试取消context
	r.GET("/test/context/cancel", func(c *gin.Context) {
		ctx, cancel := context.WithCancel(context.Background())
		startGoroutine(ctx, 100)
		// 休眠5s后取消, 模拟主动取消
		time.Sleep(time.Second * 5)
		cancel()
		// 额外休眠5s, 为了明确显示出, 后台协程退出是因为主动取消, 而不是因为函数执行完成退出
		time.Sleep(time.Second * 5)
		fmt.Println("all goroutine is finished  ", time.Now().Format(time.DateTime))
		c.JSON(http.StatusOK, gin.H{"msg": "ok! cancel"})
	})
	// 测试timeout
	r.GET("/test/context/timeout", func(c *gin.Context) {
		// 一个 10s 超时的context
		ctx, _ := context.WithTimeout(context.Background(), time.Second*10)
		startGoroutine(ctx, 100)
		// 休眠12s后返回, 模拟超时
		time.Sleep(time.Second * 12)
		fmt.Println("模拟超时完成 ", time.Now().Format(time.DateTime))
		c.JSON(http.StatusOK, gin.H{"msg": "ok! timeout"})
	})

	go func() {
		log.Fatal(http.ListenAndServe(":8888", handlers.CompressHandler(http.DefaultServeMux)))
	}()
	r.Run(":8080")
}

基础信息

# 常看pprof相关信息实时变化
http://localhost:8888/debug/charts/
# 测试cancelContext
http://localhost:8080/test/context/cancel
# 测试timeout
http://localhost:8080/test/context/timeout

CancelContext说明

打开pprof监控页面之后, 访问测试取消接口, 可以看到有100个goroutine在运行, 然后10s后取消, 可以看到100个goroutine都已经退出了

终端会有如下信息输出:

.....
goroutine  40  is running
goroutine  40  is finished   2025-05-17 23:10:13
goroutine  13  is running
goroutine  13  is finished   2025-05-17 23:10:13
goroutine  95  is finished   2025-05-17 23:10:13
goroutine  50  is finished   2025-05-17 23:10:13
all goroutine is finished   2025-05-17 23:10:18

所有协程取消退出之后, 再次休眠5s后, 才退出请求方法, 说明后台协程的退出, 是程序主动取消的, 协程监控如下:

context取消

TimeoutContext说明

打开pprof监控页面之后, 访问测试取消接口, 可以看到有100个goroutine在运行, 然后10s后取消, 可以看到100个goroutine都已经退出了

终端会有如下信息输出:

.....
goroutine  14  is running
goroutine  14  is finished   2025-05-17 23:17:41
goroutine  74  is running
goroutine  74  is finished   2025-05-17 23:17:41
goroutine  89  is finished   2025-05-17 23:17:41
模拟超时完成  2025-05-17 23:17:43

超时context配置的超时时间是10s, 但是程序在12s后才退出, 说明后台协程的退出, 是程序主动超时取消的, 协程监控如下

context超时

Released under the MIT License.