Gogoroutinecontext
让 context 负责取消,让 channel 传递数据
channel 擅长在 goroutine 之间传递值,context.WithCancel 则把退出信号沿调用链传播。长时间运行的 worker 应在每次可能阻塞的位置检查 ctx.Done()。
ctx, cancel := context.WithCancel(parent)
defer cancel()
select {
case job := <-jobs:
process(job)
case <-ctx.Done():
return ctx.Err()
}不再建议把一个永远不会写入的 done channel 到处传递;需要兼容旧代码时可以保留它,但用 context 统一入口更容易追踪超时和取消原因。
避免泄漏
- 发送方在接收者退出后可能永久阻塞;发送也要放进
select,监听ctx.Done()。 - 谁创建 channel,通常由谁关闭;不要让多个 worker 猜测何时 close。
- 关闭 channel 代表不会再有值,不等于要求消费者立刻退出;用两值接收判断
ok。
for {
select {
case v, ok := <-results:
if !ok { return }
consume(v)
case <-ctx.Done():
return
}
}
带 deadline 的 context 应由最接近请求边界的调用方创建,底层函数只接收并传递它,避免悄悄延长超时。
对 worker pool 来说,先关闭 jobs,再等待 worker 退出,最后关闭 results,能让所有权关系更清楚。