Go中获取异步结果最直接可靠的方式是从chan T接收值,因其天然支持等待、超时、取消和多路复用,无需额外抽象。

Go 里没有 Future 类型,获取异步结果最直接、最可靠的方式就是从 chan T 接收值——它天然支持等待、超时、取消和多路复用,不需要额外抽象。
用 当作 “结果句柄” 直接接收
返回只读 channel 是 Go 风格的 Future 实现。调用方不关心 goroutine 怎么跑,只关心“什么时候能拿到值”。
- 函数签名必须是
func() ,不是 <code>chan string:防止调用方误写入 - channel 缓冲大小设为
1:避免无缓冲 channel 导致 goroutine 启动即阻塞(等不到接收方) - goroutine 内必须
defer close(ch):否则接收方无法区分“任务失败没发值”和“还在跑” - 别在函数内写
return :这会同步阻塞,失去异步意义
带超时的等待必须用 select,不能只写
裸写 会永久阻塞,生产代码几乎从不这么用。超时控制是刚需,<code>select 是唯一正解。
-
select中多个case同时就绪时随机选一个,不保证顺序 - 想避免阻塞又不想等,加
default分支;想强制等待,就不要default - 超时用
time.After(d)最简单,但注意它会启动一个 timer goroutine,短时高频调用需谨慎 - 如果已有
context.Context,优先用ctx.Done()替代time.After,更利于取消传播
错误不能丢,chan Result[T] 比 chan T + chan error 更安全
只传 chan int 无法区分“成功返回 0”和“出错没返回”,这是新手最常翻车的地方。
立即学习“go语言免费学习笔记(深入)”;
- 定义
type Result[T any] struct { Value T; Err error },统一承载结果与错误 - 发送方无论成功失败都发一次
ch - 接收方一次接收、一次判断:
if r.Err != nil { … } else { use r.Value } - 千万别用
panic代替error:goroutine 内 panic 不会冒泡到主流程,recover 又难写难维护
别碰 sync.WaitGroup + 回调模拟 Future
WaitGroup 只解决“等完成”,不解决“取结果”。强行套用会导致嵌套深、错误难传、无法超时。
-
wg.Wait()返回时你还是不知道doWork()算出了什么 - 若用闭包变量 +
mutex存结果,要小心变量逃逸、竞态、以及忘记加锁 - 真正需要“首次访问才计算、之后复用”的场景,该用
sync.Once+ 全局变量或结构体字段,而不是 channel - 多个异步任务组合(类似
Promise.all),用sync.WaitGroup控制并发 + 多个带缓冲chan Result[T]收集,再统一select等待
最容易被忽略的是 channel 的方向性: 和 <code>chan 是编译期强制约束,不是可有可无的注释。写错方向,编译器立刻报错——这其实是 Go 在帮你守住 Future 模式的边界:发送和接收职责必须分离,不能混在一起。


















