竞速模式(First to Finish)指并行启动多个goroutine执行同类任务,仅取最先完成的结果并取消其余任务,适用于健康探测、DNS解析、缓存降级等场景。

什么是竞速模式(First to Finish)
竞速模式指启动多个 goroutine 并行执行同一类任务,只取最先完成的那个结果,其余全部丢弃或取消。它不是“谁快谁先跑”,而是“谁先出结果谁赢”,典型场景包括:对同一服务发起多副本健康探测、DNS解析备选路径、缓存穿透时的回源降级兜底、微服务调用的多实例冗余请求等。
用 select + done channel 实现最简竞速
核心思路是让所有 goroutine 向同一个 chan 写入结果,但主 goroutine 只读一次就退出;配合一个 done 信号通道通知其他协程提前中止。
-
make(chan int, 1):带缓冲的 result channel,确保第一个写入不阻塞,后续写入直接被丢弃(因缓冲已满) - 每个
goroutine启动前检查done是否已关闭,避免无意义执行 - 主 goroutine 在
select中设置default或超时,防止无限等待
context.WithCancel
- 不要在
select外层直接用ctx.Err()判断——那只是检查是否已取消,不能替代监听 - 如果任务本身支持
context(如http.Client.Do),应直接传入,而非自己做超时判断 - 避免在
defer中调用cancel()——这会导致上下文过早失效
goroutine
- HTTP 请求务必调用
resp.Body.Close(),哪怕你只读了状态码 - 数据库查询若用
rows.Next(),需确保循环结束或显式rows.Close() - 自定义任务里,把清理逻辑放在
select的case 分支里,而不是只靠函数返回 - 不要依赖
runtime.GC()回收——它不保证及时,也不回收 OS 级资源
真正健壮的竞速实现,永远比“谁先写 channel”多一层:它得知道怎么优雅撤退。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











