【问题标题】:Why does gorilla websocket chat example not finding it neccessary to use sync.RWMutex to access and edit maps?为什么 gorilla websocket 聊天示例不需要使用 sync.RWMutex 来访问和编辑地图?
【发布时间】:2015-12-22 16:31:39
【问题描述】:

在聊天示例中有一个名为 hub.go 的文件。

https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go

我对该文件进行了一些更改,它看起来像这样:

type hub struct {
    // Registered connections.
    connections map[int64]*connection

    sync.RWMutex

    // Inbound messages from the connections.
    broadcast chan []byte

    // Register requests from the connections.
    register chan *connection

    // Unregister requests from connections.
    unregister chan *connection
}

var wsHub = hub{
    connections: make(map[int64]*connection),
    broadcast:   make(chan []byte),
    register:    make(chan *connection),
    unregister:  make(chan *connection),
}

func (h *hub) init() {
    for {
        select {
        case c := <-h.register:
            h.Lock()
            h.connections[c.userId] = c
            h.Unlock()
        case c := <-h.unregister:
            h.RLock()
            _, ok := h.connections[c.userId]
            h.RUnlock()
            if ok {
                h.Lock()
                delete(h.connections, c.userId)
                h.Unlock()
                close(c.send)
            }
        case m := <-h.broadcast:
            for _, c := range h.connections {
                select {
                case c.send <- m:
                default:
                    close(c.send)
                    delete(h.connections, c.userId)
                }
            }
        }
    }
}

我已将 sync.RWMutex 添加到集线器结构中,但我不确定这是否有必要。为什么它没有包含在示例中?也许我错过了什么?锁定和解锁是否过大?

还有 init() 方法中的最后一种情况,我不确定如何锁定和解锁,因为它同时读取和写入。我应该同时使用 Rlock() 和 Lock() 吗?那会是什么样子?

【问题讨论】:

    标签: go


    【解决方案1】:

    不需要互斥体,因为 single hub goroutine 是唯一访问映射的 goroutine。

    另一种方法是消除 Go 例程和通道,并用使用互斥锁的函数替换它们。

    type hub struct {
      connections map[*connection]bool
      mu sync.Mutex
    }
    
    var h = hub{
       connections: make(map[*connection]bool),
    }
    
    func (h * hub) register(c *connection) {
      h.mu.Lock()
      h.connections[c] = true
    }
    
    func (h *hub) unregister(c *connection) {
      h.mu.Lock()
      if _, ok := h.connections[c]; ok {
         delete(h.connections, c)
         close(c.send)
      }
      h.mu.Unlock()
    }
    
    func (h * hub) broadcast(message []byte) {
      h.mu.Lock()
      for c := range h.connections {
        select {
        case c.send <- m:
        default:
          close(c.send)
          delete(h.connections, c)
        }
      }
      h.mu.Unlock()
    }
    

    使用互斥体保护close(c.send)c.send &lt;- m 很重要。这可以防止在关闭的通道上发送。

    【讨论】:

    • 谢谢!如果必须锁定,您将如何锁定最后一个案例?
    • 非常感谢。这很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多