本文介绍在 go websocket 服务器中,如何通过 `select` + `default` 实现通道的非阻塞写入,避免因接收方缓慢导致发送方 goroutine 被挂起,从而提升系统并发响应能力。
在构建高并发 WebSocket 服务时,常见模式是为每个客户端维护一个专属的发送通道(如 chan []byte),由独立的写 Goroutine 持续消费该通道并发送数据到网络连接。然而,当客户端网络异常、连接卡顿或读取速率远低于发送速率时,该通道可能迅速填满——若使用普通阻塞式发送 u.send
要解决这一问题,核心思路是放弃“必须立即入队”的假设,转而采用非阻塞尝试写入。Go 的 select 语句配合 default 分支正是为此设计的标准方案:
func (u *User) Send(msg []byte) error {
select {
case u.send <- msg:
return nil // 成功入队
default:
// 通道已满,无法立即写入
ret
urn errors.New("send channel is full, message dropped")
}
}该写法确保 Send() 方法始终立即返回:成功时消息入队;失败时快速反馈错误,调用方可据此做降级处理(如日志告警、重试调度、或主动断连慢客户端)。
⚠️ 注意事项:
总结而言,select { case ch