首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
上下文
上下文和普通参数的区别
上下文树
上下文接口——Context
利用context.emptyCtx创建树的根节点
上下文树的构建
利用valueCtx实现信息透传
valueCtx用于参数传递
从父节点获得透传值
利用cancelCtx通知协程终止执行
通知子协程终止执行
通知子协程的实现过程
为什么需要取消函数
利用timerCtx实现定时取消
调用context.WithDeadline()创建定时器上下文
调用context.WithTimeout()创建定时器上下文
编程范例——上下文的典型应用场景
利用结构体传递参数
valueContext为什么需要key
利用cancelCtx同时取消多个子协程
反射
反射的意义
反射的API
利用reflect.TypeOf()来获得类型信息
利用reflect.Type.Kind()方法来获取类型的具体分类
利用reflect.Type.Element()方法来获取元素类型
类型断言的用法与局限性
值信息
利用reflect.ValueOf()来获得值信息
利用reflect.Value.Kind()来获得值的分类信息
利用reflect.Value.Elem()来获得值的元素信息
利用反射访问和修改值信息
利用反射机制动态调用方法
编程范例——动态方法调用
泛型
泛型的意义
泛型应用到函数
泛型函数的使用
泛型中的隐含信息
避免类型强制转换
泛型类型的单独定义
泛型导致接口定义的变化
接口定义的变化
空接口的二义性
接口类型的限制
泛型类型应用到receiver
泛型类型不能直接用于定义receiver
间接实现泛型定义receiver
编程范例——自定义队列的实现
当前位置:
首页>>
技术小册>>
深入浅出Go语言核心编程(五)
小册名称:深入浅出Go语言核心编程(五)
### 章节标题:上下文接口——Context 在Go语言(Golang)的并发编程模型中,`context` 包扮演着至关重要的角色,它提供了一种在goroutine之间传递取消信号、超时时间、截止日期以及其他请求范围的值的方法。`Context` 接口及其实现是Go标准库`context`包的核心,它允许我们编写出更加灵活、健壮且易于测试的并发代码。本章将深入探讨`Context`接口的设计哲学、使用方法、以及最佳实践。 #### 一、Context 接口概述 `Context` 接口定义在`context`包中,是一个非常简单的接口,仅包含一个方法: ```go type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} } ``` - `Deadline()` 方法返回一个表示操作截止时间的`time.Time`值和一个布尔值`ok`。如果`Context`没有设置截止时间,`ok`将返回`false`。 - `Done()` 方法返回一个只读的`chan struct{}`通道,当`Context`被取消或达到其截止时间时,该通道将被关闭。 - `Err()` 方法在`Done`通道被关闭后返回一个非nil的错误值,表示`Context`被取消的原因。 - `Value(key interface{}) interface{}` 方法用于从`Context`中检索与`key`相关联的值。`Context`中的值通常用于跨API边界传递请求范围的元数据。 #### 二、Context 的实现 `context`包提供了几个`Context`接口的实现,包括`Background`、`TODO`、`WithCancel`、`WithDeadline`、`WithTimeout`和`WithValue`。 - **Background 和 TODO**: - `Background()` 返回一个空的`Context`,它通常用作所有`Context`树的根。 - `TODO()` 返回一个非空的`Context`,当你不确定使用哪个`Context`或者它还不存在时,可以使用`TODO()`。它主要用于标记当前`Context`缺失的情况,以便未来重构。 - **WithCancel**: - `WithCancel(parent Context) (ctx Context, cancel CancelFunc)` 返回一个父`Context`的副本,并添加一个取消函数。调用`cancel`函数或父`Context`的`Done`通道被关闭时,返回的`Context`的`Done`通道也会被关闭。 - **WithDeadline 和 WithTimeout**: - `WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)` 返回一个父`Context`的副本,并设置了一个不晚于`deadline`的截止时间。 - `WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)` 是`WithDeadline`的便捷包装,它接受一个持续时间而不是一个绝对时间。 - **WithValue**: - `WithValue(parent Context, key, val interface{}) Context` 返回一个父`Context`的副本,其中包含了与`key`相关联的`val`值。使用`Value`方法时,应使用类型安全的键(通常是自定义类型或接口),以避免键冲突。 #### 三、Context 的使用场景 `Context`在Go语言中的使用非常广泛,特别是在处理HTTP请求、数据库操作、长时间运行的后台任务等场景中。 - **HTTP 服务器**: 在HTTP服务器中,每个请求都应该有一个与之关联的`Context`,这个`Context`可以携带请求相关的元数据(如用户ID、请求ID等),并且可以在请求处理过程中被取消或设置超时。 - **数据库操作**: 当执行数据库查询或更新时,可以使用`Context`来传递取消信号或超时时间,确保在数据库操作被长时间阻塞时能够优雅地中断。 - **后台任务**: 对于需要长时间运行的任务,如定时任务、消息队列处理等,`Context`可以用来控制任务的执行周期,或者在必要时取消任务。 #### 四、最佳实践 1. **不要将`Context`存储在结构体中**: `Context`应该作为函数调用的第一个参数传递,而不是存储在结构体中。这样做可以避免在结构体被复制或传递给其他goroutine时,无意中传递了错误的`Context`。 2. **使用`context.Background()`作为根Context**: 当你需要创建一个全新的`Context`树时,应使用`context.Background()`作为根节点。 3. **传递`Context`到所有需要它的函数**: 确保所有需要`Context`的函数都接受一个`Context`参数,并在函数内部正确地使用它。 4. **不要取消非子goroutine的Context**: 只应由创建goroutine的`Context`的拥有者来取消该`Context`。如果goroutine是由其他goroutine创建的,则不应由外部取消其`Context`。 5. **使用`context.Value`传递请求范围的元数据**: 当需要在多个函数或goroutine之间传递请求范围的元数据时,应使用`context.Value`。但请注意,过度使用`context.Value`可能会导致代码难以理解和维护。 6. **优雅地处理取消和超时**: 当`Context`的`Done`通道被关闭时,应优雅地清理资源并退出函数。对于可能阻塞的操作(如I/O操作),应使用`select`语句来监听`Done`通道和其他通道。 #### 五、总结 `Context`接口是Go语言并发编程中不可或缺的一部分,它提供了一种在goroutine之间传递取消信号、超时时间和其他请求范围值的有效方式。通过合理使用`Context`,我们可以编写出更加健壮、灵活和易于测试的并发代码。在编写Go程序时,应始终遵循`Context`的最佳实践,以确保代码的质量和可维护性。
上一篇:
上下文树
下一篇:
利用context.emptyCtx创建树的根节点
该分类下的相关小册推荐:
企业级Go应用开发从零开始
go编程权威指南(二)
Go Web编程(上)
深入浅出Go语言核心编程(六)
GO面试指南
Golang并发编程实战
Go开发基础入门
深入浅出Go语言核心编程(四)
深入浅出Go语言核心编程(八)
深入浅出Go语言核心编程(二)
WebRTC音视频开发实战
go编程权威指南(四)