我研究了gorilla/websocket软件包的Godoc。
在Godoc中,明确说明了:
并发性 连接支持一个并发读取器和一个并发写入器。 应用程序有责任确保不超过一个goroutine同时调用写方法(NextWriter、SetWriteDeadline、WriteMessage、WriteJSON、EnableWriteCompression、SetCompressionLevel),并且不超过一个goroutine同时调用读方法(NextReader、SetReadDeadline、ReadMessage、ReadJSON、SetPongHandler、SetPingHandler)。 关闭和WriteControl方法可以与所有其他方法同时调用。
然而,在该包提供的一个示例中。
这行代码来源于:https://github.com/gorilla/websocket/blob/a68708917c6a4f06314ab4e52493cc61359c9d42/examples/chat/conn.go#L50 这一行代码的作用是:
在Godoc中,明确说明了:
并发性 连接支持一个并发读取器和一个并发写入器。 应用程序有责任确保不超过一个goroutine同时调用写方法(NextWriter、SetWriteDeadline、WriteMessage、WriteJSON、EnableWriteCompression、SetCompressionLevel),并且不超过一个goroutine同时调用读方法(NextReader、SetReadDeadline、ReadMessage、ReadJSON、SetPongHandler、SetPingHandler)。 关闭和WriteControl方法可以与所有其他方法同时调用。
然而,在该包提供的一个示例中。
func (c *Conn) readPump() {
defer func() {
hub.unregister <- c
c.ws.Close()
}()
c.ws.SetReadLimit(maxMessageSize)
c.ws.SetReadDeadline(time.Now().Add(pongWait))
c.ws.SetPongHandler(func(string) error {
c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil
})
for {
_, message, err := c.ws.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
log.Printf("error: %v", err)
}
break
}
message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
hub.broadcast <- message
}
}
这行代码来源于:https://github.com/gorilla/websocket/blob/a68708917c6a4f06314ab4e52493cc61359c9d42/examples/chat/conn.go#L50 这一行代码的作用是:
c.ws.SetPongHandler(func(string) error {
c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil
})
并且这一行
_, message, err := c.ws.ReadMessage()
第一行是回调函数,所以似乎没有同步,因此应该在包中创建的Goroutine中调用它,第二行在调用serveWs
的Goroutine中执行。
更重要的是,我该如何确保不超过一个goroutine并发调用SetReadDeadline
、ReadMessage
、SetPongHandler
和SetPingHandler
?
我尝试使用Mutex锁,在调用上述函数时锁定它,并稍后解锁它,但很快我意识到了一个问题。通常(也在示例中),ReadMessage
在for循环中被调用。但如果在ReadMessage之前锁定Mutext,则没有其他Read函数可以获取锁并执行,直到下一条消息被接收。
是否有更好的处理并发问题的方法?提前致谢。