一个很具体的并发问题。
多个 goroutine 启动时都需要 MQTT 客户端。连接只能初始化一次,其余调用方要等待结果。
布尔值只能表达“有人正在初始化”,不能表达“什么时候完成、结果是什么”。轮询布尔值还会引入竞态。
更合适的语义是一个完成事件:
type ClientFuture struct {
done chan struct{}
client mqtt.Client
err error
}
func (f *ClientFuture) Wait(ctx context.Context) (mqtt.Client, error) {
select {
case <-f.done:
return f.client, f.err
case <-ctx.Done():
return nil, ctx.Err()
}
}
第一个调用方完成初始化后关闭 done,所有等待者同时被唤醒,并读取同一份结果。
这不是“channel 比锁好”的例子。锁仍然负责保护 future 的创建,channel 负责广播完成。工具没有高低,只有语义是否贴合。