不是函数写错了,而是超时信号未被消费:context.withtimeout仅提供ctx.done()通道,下游函数必须显式监听该通道或调用ctx.err()判断errors.is(err, context.deadlineexceeded),且需将ctx传入http.newrequestwithcontext、querycontext等支持context的api,否则超时无效。

context.WithTimeout 调用后没超时,是不是函数写错了?
不是函数写错了,而是超时信号根本没被消费——context.WithTimeout 本身不中断任何操作,它只提供一个 ctx.Done() 通道。如果下游函数没监听这个通道,超时就纯属摆设。
- 标准库中只有显式接收
context.Context参数的函数才可能响应超时,比如http.Request.WithContext()、sql.DB.QueryContext()、net.DialContext() - 直接调用
http.Get(url)或db.Query(sql)这类老接口,哪怕外面套了WithTimeout,也完全无视超时 - 自己写的阻塞逻辑(如
time.Sleep、轮询 channel、长循环)必须手动插入if ctx.Err() != nil { return }检查点 - 错误判断别用字符串匹配:
errors.Is(err, context.DeadlineExceeded)才是正确方式,err == context.DeadlineExceeded在 Go 1.20+ 可能失效
HTTP 请求超时为什么总是报 “Client.Timeout exceeded” 而不是 “context deadline exceeded”?
因为底层 http.Transport 的超时设置早于 context 触发,把请求截断在更早环节,导致你设的 context.WithTimeout 根本没机会生效。
-
http.Client.Timeout是兜底总超时,覆盖 DNS + dial + write + read 全流程;它优先级低于 context,但会强制中断已发起的操作 -
http.Transport有更细粒度控制:比如DialContext默认 30 秒建连、ResponseHeaderTimeout默认 60 秒等,若这些值小于你的 context 超时,就会先报Client.Timeout exceeded - 推荐做法:把
http.Client.Timeout设为0(禁用),所有超时由 context 控制;同时确保Transport各项 timeout ≥ context 超时值 - 必须用
http.NewRequestWithContext(ctx, ...)构造请求,再交给client.Do(),不能跳过这步
为什么 defer cancel() 之后还是内存增长?
因为你漏掉了 panic 恢复、select default 分支、或提前 return 的路径——cancel() 必须在所有退出路径上执行,否则 timer 和内部 channel 会持续泄漏。
-
ctx, cancel := context.WithTimeout(parentCtx, 3*time.Second)必须接收cancel函数,写成ctx, _ := ...就注定泄漏 -
defer cancel()只覆盖正常返回路径;HTTP handler 中遇到 panic、return提前退出、或select走了default,都会跳过 defer - 常见修复模式:在 handler 开头定义
var cancel context.CancelFunc,赋值后在所有出口(包括 recover 块)显式调用cancel() - 超时触发后仍要调
cancel():Go 不会自动清理 timer,即使ctx.Err() == context.DeadlineExceeded已成立,不调cancel()就不释放资源
超时时间是从哪一刻开始算的?
从 context.WithTimeout 被调用的那一行代码执行完开始计时,不是从网络请求发出、SQL 查询执行、或 goroutine 启动那一刻起算。
- 中间任何延迟都会吃掉超时预算:比如 handler 入口就创建超时 ctx,但后续卡在锁里 800ms,再发 HTTP 请求时只剩 1.2 秒可用
- 想真正“从 IO 发起时刻计时”,就得把
WithTimeout放在 IO 操作前最后一刻,而不是 handler 顶层 - 嵌套多个
WithTimeout时,外层超时包含内层创建开销,总耗时不等于各层之和 - 测试时慎用
time.Sleep模拟耗时:它不触发调度器抢占,timer 实际触发可能比预期晚几十毫秒
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











