首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
本小册内容介绍
本小册内容综述
Go语言简介:历史背景、发展现状及语言特性
编写第一个Go程序
变量、常量以及与其他语言的差异
数据类型
运算符
条件和循环
数组和切片
Map声明、元素访问及遍历
Map与工厂模式,在Go语言中实现Set
字符串
Go语言的函数
可变参数和defer
行为的定义和实现
Go语言的相关接口
扩展与复用
不一样的接口类型,一样的多态
编写好的错误处理
panic和recover
构建可复用的模块(包)
依赖管理
协程机制
共享内存并发机制
CSP并发机制
多路选择和超时
channel的关闭和广播
任务的取消
Context与任务取消
只运行一次
仅需任意任务完成
所有任务完成
对象池
sync.pool对象缓存
单元测试
Benchmark
BDD
反射编程
万能程序
不安全编程
实现pipe-filter framework
实现micro-kernel framework
内置JSON解析
easyjson
HTTP服务
构建RESTful服务
性能分析工具
性能调优示例
别让性能被锁住
GC友好的代码
高效字符串连接
面向错误的设计
面向恢复的设计
Chaos Engineering
当前位置:
首页>>
技术小册>>
Go语言从入门到实战
小册名称:Go语言从入门到实战
### 任务的取消 在Go语言编程中,任务的取消是一个重要且实用的功能,它允许程序在必要时优雅地中断正在执行的操作,以释放资源、避免资源浪费或响应外部事件。这一机制在处理长时间运行的后台任务、网络请求、文件操作或是任何可能需要提前终止的场景中尤为关键。本章将深入探讨Go语言中实现任务取消的几种方法,包括使用`context`包、通过通道(channel)传递取消信号,以及结合Go的并发模型来构建高效、可维护的取消逻辑。 #### 一、`context`包简介 在Go 1.7版本中引入的`context`包,为在Go程序中传递取消信号、截止时间、以及其他请求范围的值提供了一种标准方法。`context.Context`接口是这一机制的核心,它定义了四个主要方法: - `Deadline() (deadline time.Time, ok bool)`: 返回设置的截止时间(如果有的话),如果没有设置则返回零值和`false`。 - `Done() <-chan struct{}`: 返回一个只读的通道,当操作被取消或截止时间到达时,该通道会被关闭。 - `Err() error`: 如果Done通道被关闭,返回取消的错误原因;如果Done没有被关闭,则返回`nil`。 - `Value(key interface{}) interface{}`: 用于从Context中获取键对应的值。 #### 二、使用`context`实现任务取消 在Go程序中,你可以通过`context.WithCancel`、`context.WithTimeout`、`context.WithDeadline`等函数来创建具有取消功能的`Context`对象。下面,我们将通过示例来展示如何使用这些函数来实现任务的取消。 ##### 2.1 使用`context.WithCancel` `context.WithCancel`函数返回一个`Context`对象和一个取消函数。调用取消函数将关闭返回的`Context`的Done通道,从而触发所有监听该通道的goroutine执行取消逻辑。 ```go package main import ( "context" "fmt" "time" ) func longRunningTask(ctx context.Context) { select { case <-time.After(5 * time.Second): fmt.Println("Task completed normally") case <-ctx.Done(): fmt.Println("Task cancelled:", ctx.Err()) } } func main() { ctx, cancel := context.WithCancel(context.Background()) go longRunningTask(ctx) // 假设在1秒后我们决定取消任务 time.Sleep(1 * time.Second) cancel() // 等待足够长的时间以确保任务完成或取消 time.Sleep(2 * time.Second) } ``` ##### 2.2 使用`context.WithTimeout`和`context.WithDeadline` 这两个函数分别用于设置操作的超时时间和绝对截止时间。当到达指定的时间点时,它们会自动取消`Context`,从而触发取消逻辑。 ```go package main import ( "context" "fmt" "time" ) func main() { // 使用WithTimeout ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // 避免内存泄露 go func() { <-ctx.Done() fmt.Println("Task cancelled or timed out:", ctx.Err()) }() time.Sleep(3 * time.Second) // 等待足够长的时间以确保任务超时 // 使用WithDeadline now := time.Now() deadline := now.Add(1 * time.Second) ctx, cancel = context.WithDeadline(context.Background(), deadline) defer cancel() go func() { <-ctx.Done() fmt.Println("Task cancelled due to deadline:", ctx.Err()) }() time.Sleep(2 * time.Second) // 等待足够长的时间以确保任务因截止时间到达而取消 } ``` #### 三、通过通道传递取消信号 除了使用`context`包之外,Go的通道(channel)也是实现任务取消的一种有效方式。特别是在`context`包引入之前,许多项目都采用了这种方式。尽管现在推荐使用`context`,但理解其背后的原理仍然很有价值。 ```go package main import ( "fmt" "time" ) func longRunningTask(cancelChan <-chan struct{}) { select { case <-time.After(5 * time.Second): fmt.Println("Task completed normally") case <-cancelChan: fmt.Println("Task cancelled") } } func main() { cancelChan := make(chan struct{}) go longRunningTask(cancelChan) // 假设在1秒后我们决定取消任务 time.Sleep(1 * time.Second) close(cancelChan) // 等待足够长的时间以确保任务完成或取消 time.Sleep(2 * time.Second) } ``` 在这个例子中,我们创建了一个无缓冲的通道`cancelChan`,并将其作为参数传递给`longRunningTask`函数。当需要取消任务时,我们简单地关闭了该通道,这会导致任何在该通道上执行`<-cancelChan`操作的goroutine接收到一个零值(因为是无缓冲通道,且没有数据发送,关闭通道即视为发送了取消信号)。 #### 四、最佳实践与注意事项 1. **尽可能使用`context`包**:`context`是Go官方推荐的传递请求范围值(包括取消信号)的方式,它提供了比裸通道更丰富的功能和更好的类型安全。 2. **避免泄露Context**:确保在不再需要`Context`时调用其`cancel`函数,以避免资源泄露。使用`defer cancel()`是一种常见的做法,但需注意其在函数返回前的行为。 3. **传递Context而非取消信号**:在函数间传递时,尽量传递整个`Context`对象而非单独的取消信号,这样接收方可以访问`Context`中的其他值(如截止时间、用户信息等)。 4. **优雅处理取消**:在goroutine中,应优雅地处理取消事件,确保资源被正确释放,避免留下悬挂的goroutine或未关闭的文件句柄等。 5. **避免在Context中存储大量数据**:`Context`应主要用于传递跨API边界的少量关键数据,大量数据的传递应通过其他机制(如参数列表、结构体等)来实现。 通过本章的学习,你应该对Go语言中任务的取消机制有了深入的理解,并能够在实际项目中灵活运用`context`包或通道来实现任务的取消逻辑。这将有助于你编写出更加健壮、灵活和易于维护的Go程序。
上一篇:
channel的关闭和广播
下一篇:
Context与任务取消
该分类下的相关小册推荐:
go编程权威指南(二)
深入浅出Go语言核心编程(四)
深入浅出Go语言核心编程(五)
深入浅出Go语言核心编程(八)
Go 组件设计与实现
从零写一个基于go语言的Web框架
Go Web编程(上)
Go开发权威指南(下)
go编程权威指南(一)
WebRTC音视频开发实战
深入浅出Go语言核心编程(七)
Go语言入门实战经典