Go语言中goroutine的取消依赖context包实现协作式退出。通过context.WithCancel创建可取消的context并传递给子goroutine,调用cancel()后,监听ctx.Done()的goroutine会收到信号并退出;还可使用context.WithTimeout或WithDeadline设置超时自动取消,适用于网络请求等场景;关键在于goroutine需主动检查ctx.Done()并清理资源,确保安全退出。

在Go语言中,goroutine的取消机制主要依赖于context包。由于goroutine一旦启动就无法被外部直接停止,因此需要一种协作式的方式来通知它退出。使用context.Context是官方推荐的做法,它可以传递取消信号、超时和截止时间等信息。
使用Context实现取消机制
context.Context 是处理取消的核心工具。通过父goroutine创建可取消的context,并将其传递给子goroutine。当调用cancel()函数时,所有监听该context的goroutine都会收到取消信号。
基本模式如下:
- 调用
context.WithCancel创建一个可取消的context - 将context传入正在运行的goroutine
- 在goroutine内部监听
ctx.Done()通道 - 接收到信号后清理资源并退出
示例代码:
立即学习“go语言免费学习笔记(深入)”;
package mainimport ( "context" "fmt" "time" )
func worker(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("收到取消信号,退出goroutine") return default: fmt.Println("工作中...") time.Sleep(500 * time.Millisecond) } } }
func main() { ctx, cancel := context.WithCancel(context.Background()) go worker(ctx)
time.Sleep(2 * time.Second) cancel() // 发送取消信号 time.Sleep(1 * time.Second) // 等待worker退出}
带超时的自动取消
除了手动调用
cancel(),还可以设置超时或截止时间,让context自动触发取消。常用方法有:
-
context.WithTimeout(ctx, duration):设定相对时间后自动取消 -
context.WithDeadline(ctx, time.Time):设定具体时间点后取消
适用于网络请求、数据库查询等可能阻塞的操作。
示例:超时自动取消
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel()go worker(ctx) // 3秒后context会自动关闭,worker收到Done信号
确保资源释放与清理
取消并不意味着立即终止,goroutine需要主动响应取消信号并完成必要的清理工作,比如关闭文件、释放锁、断开连接等。
关键点:
- 始终检查
ctx.Done(),不要忽略取消信号 - 使用
defer确保资源释放 - 避免在取消后继续写入channel,防止panic
- 多个goroutine共享同一个context时,一个取消全部响应
基本上就这些。合理使用context能让并发程序更可控、更安全。核心在于“协作”——发起方发出信号,执行方主动退出。不复杂但容易忽略细节。










