使用context包可优雅取消Go并发任务,核心是通过WithCancel、WithTimeout或WithDeadline创建上下文,将ctx传递给goroutine,调用cancel()函数通知任务停止,子goroutine监听ctx.Done()并清理退出,避免资源泄露。

在Golang中,要优雅地取消并发任务,
context
context.Done()
要取消并发任务,核心思路是创建一个带有取消功能的
context
context
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, id int) {
fmt.Printf("Worker %d: 启动...\n", id)
for {
select {
case <-ctx.Done():
// 接收到取消信号
fmt.Printf("Worker %d: 收到取消信号,正在清理并退出。错误信息: %v\n", id, ctx.Err())
return
case <-time.After(500 * time.Millisecond):
// 模拟工作
fmt.Printf("Worker %d: 正在处理任务...\n", id)
}
}
}
func main() {
// 创建一个可取消的context
ctx, cancel := context.WithCancel(context.Background())
// 启动一个worker goroutine
go worker(ctx, 1)
// 让worker运行一段时间
time.Sleep(2 * time.Second)
fmt.Println("Main: 准备发送取消信号...")
// 发送取消信号
cancel()
fmt.Println("Main: 取消信号已发送。")
// 等待worker有时间处理取消信号并退出
time.Sleep(1 * time.Second)
fmt.Println("Main: 程序退出。")
}在这个例子中,
main
context.WithCancel(context.Background())
context
cancel
ctx
worker
worker
select
ctx.Done()
main
cancel()
ctx.Done()
worker
我经常看到一些初学者在处理并发任务取消时,会本能地想到用一个
bool
context.Context
立即学习“go语言免费学习笔记(深入)”;
想象一下,你有一个HTTP请求,这个请求可能会触发数据库查询、RPC调用、文件操作等一系列子任务。如果客户端在请求完成前就断开了连接,或者请求超时了,我们肯定不希望后端那些还在忙活的子任务继续占用资源。如果没有
context
cancelCh chan struct{}context.Context
context
context
cancel()
context
context
context
context.WithCancel(parent Context)
context
cancel
cancel()
cancel
defer cancel()
context.WithTimeout(parent Context, timeout time.Duration)
context
cancel
timeout
cancel()
context
timeout
context
context.WithDeadline(parent Context, deadline time.Time)
WithTimeout
WithDeadline
deadline
context
WithTimeout
在实际开发中,我发现
WithTimeout
WithCancel
WithDeadline
在使用
context
常见陷阱:
cancel()
context.WithCancel
WithTimeout
WithDeadline
cancel
context
cancel
context
context
context
// 错误示例:在循环中忘记调用cancel
for i := 0; i < 5; i++ {
ctx, _ := context.WithCancel(context.Background())
go func(c context.Context) {
<-c.Done()
fmt.Println("Done")
}(ctx)
// 这里的cancel()没有被调用
}ctx.Done()
ctx.Done()
context
context
nil
context
context.Background()
context.TODO()
context
nil
context.WithCancel
context
context
context
最佳实践:
defer cancel()
context.WithCancel
WithTimeout
WithDeadline
context
defer cancel()
cancel
ctx, cancel := context.WithCancel(parentCtx) defer cancel() // 确保在函数退出时调用cancel // ... 使用ctx ...
context
context.Context
ctx
func fetchData(ctx context.Context, userID string) ([]byte, error) {
// ...
}ctx.Done()
select { case <-ctx.Done(): ... }context.Background()
context.TODO()
context.Background()
context
context.TODO()
context
ctx.Done()
ctx.Err()
context.Canceled
context.DeadlineExceeded
遵循这些原则,可以帮助你构建出更加健壮、高效且易于维护的Go并发程序。
以上就是Golang使用context取消并发任务示例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号