不一定。context取消后goroutine不会自动退出,仅收到退出信号;是否退出、何时退出及是否清理干净取决于goroutine自身是否监听、响应并正确处理;cancel()关闭context.Done()返回的只读channel。

不一定。context取消后,goroutine不会自动退出,它只是收到一个“该退出了”的信号;是否退出、何时退出、是否清理干净,完全取决于goroutine自己有没有监听、有没有响应、有没有正确处理。
取消信号只是通知,不是指令
context.Done() 返回一个只读 channel,cancel() 调用后它会被关闭,监听它的 select 或
- 如果 goroutine 完全没检查 ctx.Done(),它会一直运行到 main 结束或程序崩溃
- 如果只在循环开头检查一次,但内部阻塞(比如卡在无缓冲 channel 发送),可能永远收不到信号
- 如果检查了但没做任何清理(如关闭文件、释放锁、退出循环),资源就可能泄漏
常见“假响应”陷阱
很多代码看似用了 context,实则响应无效:
- 只在 for 循环外检查一次:ctx.Done() 只测一次,后续执行不受控
- select 中漏掉 default 分支且无其他 case 就绪:可能永久阻塞在
- 在 defer 中关资源,但主逻辑已 panic 或死循环:defer 根本不执行
- 子 goroutine 用的是父 context,但 cancel 是在父 goroutine 外调用的:信号能传到,但子 goroutine 可能因设计缺陷忽略它
真正可靠的退出结构长这样
一个健壮的可取消 goroutine 应该满足三个条件:持续监听、及时响应、确保清理。
- 用 select 在关键等待点监听 ctx.Done(),而不是靠轮询或单次判断
- 收到 Done 后立刻 break 循环或 return,避免继续执行业务逻辑
- 在 return 前用 defer 或显式语句关闭连接、释放锁、关闭 channel、注销回调等
- 若涉及多个子 goroutine,应传递派生 context(如 WithCancel/WithTimeout),并统一由上层 cancel 控制
main 退出时的“兜底行为”不是保障
有资料说“main 函数返回,所有 goroutine 都会被打断”,这没错,但这是进程级强制终止,不是优雅退出。此时:
- defer 不会执行
- 未 flush 的日志、缓存、数据库事务可能丢失
- 系统资源(如 TCP 连接、文件句柄)由 OS 回收,但服务端可能误判为异常断连
- 这属于崩溃式收尾,不能当作 context 取消的替代方案










