Go语言用chan T实现Future最自然可靠:make(chan T, 1)启动goroutine执行并发送结果后关闭channel,无缓冲chan会导致goroutine阻塞。

Go 语言没有内置 Future 类型,但用 chan T 并发获取多个异步任务结果,是最自然、最可靠的方式。别套 Java/JS 的 Future 接口,否则容易写出阻塞、泄漏、错误难捕获的代码。
用 make(chan T, 1) 启动单个异步任务并取结果
这是最简可行的 “future” 封装:返回只读 channel,内部启动 goroutine 执行逻辑,完成即发值 + 关闭 channel。
-
make(chan int, 1)是底线 —— 用make(chan int)(无缓冲)会导致 goroutine 启动后立刻卡在ch ,因为调用方还没开始接收 - 必须
defer close(ch):否则接收方无法区分“任务失败退出”和“还在跑”,range或select会永远等下去 - 返回类型写成
,防止调用方误向 channel 写入 - 错误要一并传回,比如用
struct{Data int; Err error}包装,不能只靠 channel 关闭判断成功
func fetchUser() <-chan struct{ Data int; Err error } {
ch := make(chan struct{ Data int; Err error }, 1)
go func() {
defer close(ch)
id, err := callAPI()
ch <- struct{ Data int; Err error }{Data: id, Err: err}
}()
return ch
}并发启动多个任务并统一收集结果
多个独立子任务(如查用户、查订单、查配置)需并行执行,且主流程要等全部完成再继续 —— 这是典型场景,核心是避免手动管理 sync.WaitGroup 和回调嵌套。
- 每个任务函数都返回
,而不是直接启动 goroutine - 用
for range配合切片收集所有 channel,再用select或简单循环接收(若顺序不敏感,直接<-ch即可) - 别用
WaitGroup+ 回调:错误传递麻烦、无法超时、取消困难;channel 天然支持select超时和取消 - 如果任务间有依赖或需要按完成顺序处理,改用
select配合多个<-ch,而非固定顺序for循环
带上下文取消和超时的 future 模式
真实服务中,异步任务不能无限等待,必须响应 context.Context 的取消或超时信号,否则会拖垮整个请求生命周期。
立即学习“go语言免费学习笔记(深入)”;
- 把
ctx传进 goroutine,用select监听ctx.Done(),并在退出前close(ch) - 不要在 goroutine 内部用
time.Sleep模拟超时 —— 它不响应 cancel,应统一走ctx.WithTimeout - 发送错误时,优先发
Result{Err: ctx.Err()},而不是静默退出,让调用方能区分是超时还是业务失败 - channel 容量仍为 1:即使超时,也要确保能发一次错误值,否则调用方
<-ch会永久阻塞
func fetchWithCtx(ctx context.Context) <-chan Result {
ch := make(chan Result, 1)
go func() {
defer close(ch)
select {
case <-ctx.Done():
ch <- Result{Err: ctx.Err()}
return
default:
}
res, err := heavyWork()
ch <- Result{Data: res, Err: err}
}()
return ch
}最容易被忽略的是 channel 关闭时机和错误封装方式:不 close 就没法判断“已完成”,不传 Err 就没法区分“空结果”和“失败”。这两个点一旦漏掉,调试时往往卡在接收端死等,而源头早已 panic 或静默退出。


















