一个常见的场景:有一个接口请求需要较长的时间(如5秒),那么,用户很可能等不及,直接就放弃了请求。
而这个接口的任务,如果在用户放弃请求后依然继续执行,那么就是浪费服务器的资源了。
所以,我们需要在得知请求中断后,主动结束耗时的任务。
context 
然而这个问题的核心是如何得知http的请求是否中断。这个问题在网上居然没什么资料。。。
示例演示
taskFunc1taskFunc2 
// 该方法模拟进行任务,需要1秒钟
func taskFunc1(ctx context.Context, end chan string) {
	// 监听任务执行情况的协程
	result := make(chan string)
	// 启动协程执行任务
	go func() {
		time.Sleep(1 * time.Second)
		result <- "success" // 5秒后完成任务,将结果写入信道
	}()
	// 监听 context的结束信号和任务结束的信号,哪个先到就先执行哪个
	select {
	case <-ctx.Done():
		end <- "taskFunc1失败"
	case <-result:
		end <- "taskFunc1成功"
	}
}
// 该方法模拟进行任务,需要5秒钟,和上面是一样的
func taskFunc2(ctx context.Context, end chan string) {
	result := make(chan string)
	go func() {
		time.Sleep(5 * time.Second)
		result <- "success"
	}()
	select {
	case <-ctx.Done():
		end <- "taskFunc2失败"
	case <-result:
		end <- "taskFunc2成功"
	}
}
 
他们内容都是一样的,都有两个参数:
ctx context.Contexthttp请求上文任务下文end chan string 
接下来实现一个接口:
// 1.一个测试接口
func Test1(c *gin.Context) {
	ctx := c.Request.Context() // 获取http请求的上下文对象
	// 主线程判断两个协程是否运行结束的信道
	end1 := make(chan string)
	end2 := make(chan string)
	// 启动两个协程分别完成任务
	go taskFunc1(ctx, end1)
	go taskFunc2(ctx, end2)
	// 监听两个协程是否结束
	err2, err1 := <-end2, <-end1
	fmt.Println(err1, err2)
}
 
taskFunc2 
taskFunc2taskFunc2 
gin.Context
gin.ContextContext 
context 
gin.Context.Request.Context() 
适用场景
contextgin.Context 
mongo-drivergo-rediscontext.Context 
context.TODO()context 
context 
于是现在也就知道了mongodb和redis要求传入这个参数的意义了:就是为了让我们能够主动结束它的任务,而不至于浪费资源继续请求数据,毕竟数据库资源是宝贵的。
当然,我们有必要每次都将gin的Context传入这些api吗?其实没有必要,因为大多数对数据库资源的请求也就是那么几十毫秒,为了节省这点资源,我们的代码需要多写很多,个人认为不需要做这种意义不大的事。
所以,我们还是针对一些特定的场景才使用,比如某些任务需要很长的时间等等。
context.TODO() 
那么,为什么gorm对数据库的操作又不需要这个参数呢?还没了解过,以后再说