本文介绍在 go websocket 服务器中,如何通过 select + default 实现通道的非阻塞写入,避免因接收方缓慢导致的 goroutine 阻塞,提升服务整体响应性和稳定性。
在构建高并发 WebSocket 服务器时,常见的模式是为每个客户端(如 User)分配独立的发送通道(chan []byte),由专属的写协程从该通道读取消息并发送到网络连接。然而,当客户端网络异常、连接卡顿或写协程

Go 语言本身不支持“带超时/错误返回的通道发送”,但可通过 select 语句配合 default 分支优雅实现非阻塞发送:
func (u *User) Send(msg []byte) error {
select {
case u.send <- msg:
return nil // 发送成功
default:
// 通道已满,无法立即发送
return errors.New("send channel full: message dropped or backpressure required")
}
}该写法的核心在于:select 会尝试执行所有可用的 case;若 u.send 通道未满,则立即执行发送;若通道已满(即无 goroutine 正在接收),则跳过该 case,进入 default 分支——整个过程零阻塞、毫秒级完成。
⚠️ 注意事项:
func (u *User) SendCtx(ctx context.Context, msg []byte) error {
select {
case u.send <- msg:
return nil
default:
select {
case u.send <- msg:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
}总结:select { case ch