pointers - References in go - attribute doesn't change -
i'm having hard time understanding how references in go work. want write simple in-memory publish-subscribe mechanism. here's code:
package sockets import ( "fmt" "github.com/gorilla/websocket" ) type hubsingleton struct { clients map[string][]*websocket.conn } var instance *hubsingleton func hub() *hubsingleton { if instance == nil { fmt.println("new instance created") instance = &hubsingleton{} } instance.clients = make(map[string][]*websocket.conn, 6) return instance } func (hub *hubsingleton) subscribe(channel string, socket *websocket.conn) error { if _, ok := hub.clients[channel]; !ok { hub.clients[channel] = make([]*websocket.conn, 0) } hub.clients[channel] = append(hub.clients[channel], socket) fmt.println("subscribe: ", hub.clients) return nil } func (hub *hubsingleton) publish(channel string, message interface{}) { fmt.println("publish: ", hub.clients) if _, ok := hub.clients[channel]; !ok { return } := 0; < len(hub.clients[channel]); i++ { conn := hub.clients[channel][i] conn.writejson(message{status: "ok", content: message}) } }
the problem seems every time call hub().publish() or hub().subscribe() new hubsingleton.client created. well, i'm not sure happens, here's output of running program:
publish: map[] subscribe: map[chan:[0xc820170000]] publish: map[] subscribe: map[chan:[0xc82008ac80]] publish: map[] publish: map[] publish: map[] subscribe: map[chan:[0xc820170140]] publish: map[]
subscribers added map disapear every time call hub(). can do, make changes in map preserved between calls?
the hub
function creates new client map on every call. change function to:
func hub() *hubsingleton { if instance == nil { fmt.println("new instance created") instance = &hubsingleton{} instance.clients = make(map[string][]*websocket.conn, 6) } return instance }
if first call hub
request handler, there's data race on instance
. use lock fix race:
var ( instance *hubsingleton mu sync.mutex ) func hub() *hubsingleton { mu.lock() defer mu.unlock() if instance == nil { fmt.println("new instance created") instance = &hubsingleton{} instance.clients = make(map[string][]*websocket.conn, 6) } return instance }
a simpler approach initialize instance once before use:
var instance *hubsingleton func newhub() *hubsingleton { return &hubsingleton{clients: make(map[string][]*websocket.conn, 6)} } func main() { instance = newhub() ... }
if publish
, subscribe
called concurrently handlers, there data races on clients
in publish
, subscribe
.
Comments
Post a Comment