go context 简记

47 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天 在go语言中,有一个和其他语言都不太相同的地方,就是context。 你可能在各种的函数签名中看到了context.Context,这个东西是干嘛的呢?

context.Context是一个接口,它定义了一个函数Done(),返回一个channel,这个channel在context被取消的时候会被关闭。 换句话说,它为我们提供了一个取消操作的机制,我们可以通过这个机制来取消一个正在执行的操作。

比如说说有时候我们需要从一个http server中获取数据,但是我们不想等待太久,如果超过了一定的时间,我们就不想再等了,这个时候我们就可以通过context来取消这个操作。

我们需要通过context.WithTimeout来创建一个context,这个context会在超时的时候被取消。

具体的原理是context会提供一个channel,当超时的时候,这个channel会被关闭,这个时候我们就可以通过select来监听这个channel,当这个channel被关闭的时候,我们就可以执行一些操作,比如说取消一个正在执行的操作。

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    select {
    case <-time.After(3 * time.Second):
        fmt.Println("end")
    case <-ctx.Done():
        fmt.Println(ctx.Err()) // prints "context deadline exceeded"
    }
}

这个代码会在两秒的时候打印出错误信息,因为我们设置了超时时间为2秒。

具体到实际应用上一些逻辑可以换成实际要用的逻辑就行了。

这个其实是很重要的,比如我们调用别人的服务,当然可能会想要在太慢时取消,不然一直卡着容易浪费资源。

这次大项目里有一个上传文件的接口,app里的设计就是在上传用时太久了的时候就取消,对应到我们使用的http框架也是这样的,通过context来实现的。就像gorm也有withContext这样的方法,也是为了实现取消操之类的功能。

当然好不好用则另说,像Java它每个线程由线程自带的一个ThreadLocal来保存一些数据,看起来其实要简洁一些。