Go 并发编程提示词(goroutine 泄漏排查、channel 用法、context 取消、errgroup 限制并发)

写 Go 并发代码(批量调用、生产者消费者、超时控制)或者服务 goroutine 数量持续上涨、偶发死锁时用:让 AI 审查或编写并发代码,确保每个 goroutine 都有退出路径、channel 由谁关闭清楚、context 能逐层取消,并给出用 pprof 定位泄漏的方法。

NNathaniel bigo··原创首发·AI 辅助撰写
通用大模型 对话模型通用
你是一名精通 Go 并发模型的后端工程师。请帮我处理下面的并发问题。

- 任务:[审查代码/编写代码/排查泄漏]
- Go 版本:[Go 版本](例:1.23)
- 场景描述:[并发场景](例:并发调用 3 个下游接口,任一失败就取消其余)
- 现象(排查时填写):[现象](例:goroutine 数量每天涨几万)
- 代码:
  [粘贴代码]

检查与编写时遵循这些原则,并逐条说明代码是否满足:
1. 每个启动的 goroutine 都必须有明确的退出条件:谁负责通知它结束、在什么情况下结束。
2. channel:
   - 由发送方关闭,接收方不关闭;多个发送方时用额外的同步手段确定关闭时机;
   - 无缓冲 channel 的发送在没有接收者时会永久阻塞,这是最常见的泄漏原因(例如超时返回后,后台 goroutine 仍在尝试发送结果);
   - 对 nil channel 读写会永久阻塞;向已关闭的 channel 发送会 panic。
3. context:
   - 从入口一路向下传递,不保存在结构体中;
   - 所有可能阻塞的操作(网络、等待 channel、sleep)都要和 context 的取消一起 select;
   - 用 WithTimeout 或 WithCancel 创建的 context,要调用返回的 cancel 释放资源。
4. 并发上限:大批量任务不能无限制地启动 goroutine,使用 errgroup 的并发限制或工作池;说明 errgroup 在第一个错误发生后如何取消其他任务。
5. 共享数据:用互斥锁保护还是通过 channel 传递所有权;提醒用竞态检测运行测试。
6. panic:goroutine 内的 panic 不会被调用方的 recover 捕获,需要时在 goroutine 内部处理。

排查泄漏时:给出用 pprof 查看 goroutine 堆栈的方法,教我从堆栈中找出「大量 goroutine 阻塞在同一行」的位置。

输出:问题清单(位置 | 问题 | 后果)、修改后的完整代码、对应的测试(包含竞态检测的运行命令)。

高亮处换成你自己的内容:[审查代码/编写代码/排查泄漏]、[Go 版本]、[并发场景]、[现象]、[粘贴代码]

ChatGPT Plus 充值

已被复制 0 次

使用说明

怎么填变量:[现象] 排查泄漏时最好附上 pprof 的 goroutine 汇总(哪一行阻塞了多少个),AI 可以直接定位。审查代码时把启动 goroutine 的函数和它使用的 channel 定义一起贴上。

常见坑:

  • 用 select 加超时实现「最多等 3 秒」,超时后函数返回了,但负责干活的 goroutine 还在尝试把结果发到无缓冲 channel 里,永远没人接收,于是泄漏。给 channel 一个缓冲位,或者让发送也监听取消信号。
  • 创建了带超时的 context 却没有调用 cancel,定时器要等到超时才释放。
  • 每来一个请求启动一个 goroutine 去处理一批子任务,没有上限,高峰期内存暴涨。

追问技巧:追问「为这段代码写一个测试,在测试结束时检查没有遗留的 goroutine」,或「把这个模式改写成可复用的工作池」。

示例输出

示例,仅供参考(并发调用多个下游,任一失败即取消其余)
go
func FetchAll(ctx context.Context, ids []string) ([]Result, error) {
	g, ctx := errgroup.WithContext(ctx) // 任一任务返回错误时,ctx 被取消
	g.SetLimit(8)                       // 最多 8 个并发
	results := make([]Result, len(ids)) // 每个 goroutine 写自己的下标,无需加锁

	for i, id := range ids {
		g.Go(func() error {
			r, err := fetchOne(ctx, id) // fetchOne 内部必须响应 ctx 取消
			if err != nil {
				return fmt.Errorf("fetch %s: %w", id, err)
			}
			results[i] = r
			return nil
		})
	}
	if err := g.Wait(); err != nil {
		return nil, err
	}
	return results, nil
}

说明:Go 1.22 起循环变量每次迭代都是新变量,闭包中直接使用 i、id 是安全的;更早的版本需要在循环内重新赋值。

bash
go test -race ./...

同款作品

用这条提示词做出来的作品;原作者会因此获得积分

做同款

还没有同款,来做第一个。

Nathaniel 的更多内容

同主题

同模型

0 条评论

登录 后参与评论

还没有评论,来抢沙发~