<p>I've not done something like this outside of JS, where it's all about events, and I'm a little unsure of what best practices would be. I'd really appreciate any more experienced Go users who could offer some advice.</p>
<p>I'm writing an application where users can add friends, and then their activities are broadcast to their friends over a websocket connection. </p>
<p>I want to account for the fact that a user might be logged in to multiple sessions at once. So my first thought was that I could store all the connections in a map where the keys are user IDs, and the values are arrays/slices of <code>websocket.Conn</code>s. When a user dispatches a message, the server would do something like</p>
<pre><code>for _, userID := range user.Friends {
for _, conn := range pool[userID] {
// conn.WriteJSON etc
}
}
</code></pre>
<p>When a user logs in, the server would check if the pool already has a key with their user ID, and if so, it'd <code>append(pool[userID], &newConn)</code>, and if not, <code>pool[userID] = []*websocket.Conn{&newConn}</code>.</p>
<p>My first concern with that is that this would be a global variable potentially being modified by multiple threads/goroutines at once, and the regular map isn't safe for concurrent use. I looked into the new map structure in the sync package, but I'm not sure whether to use it, because it warns that it's slower and not type safe relative to a normal map with a mutex. So should I just be using a mutex?</p>
<p>My other area of uncertainty is in how to implement the websocket listeners themselves. Right now, I have a regular HTTP HandleFunc that upgrades the HTTP request to a websocket connection, then does an infinite <code>for</code> loop listening for messages coming through. This is a goroutine per session, right, HandleFuncs create a new goroutine? Is that a reasonable/smart way to handle this?</p>
<hr/>**评论:**<br/><br/>wybiral: <pre><p>As far as the concurrent map situation goes I'd use a mutex. It's also really common to see people using channels to coordinate stuff like this but imo that can quickly get messy. If you look at the Go standard library code this is the kind of thing where a mutex tends to be used because it's more concise and efficient.</p>
<p>Using the sync.Map implementation seems messier to me because it loses the type safety by being defined as empty interfaces. Yuck.</p>
<p>If, however, you find yourself adding more state changes like this it might make sense to have one goroutine process them all and then communicate with that goroutine using channels as a form of internal API to synchronize those changes. But given your current problem I'd vote on using a mutex.</p>
<p>For websocket connects I would suggest Gorilla Websockets: <a href="http://www.gorillatoolkit.org/pkg/websocket" rel="nofollow">http://www.gorillatoolkit.org/pkg/websocket</a></p></pre>ChurroLoco: <pre><p>I agree with the mutex approach above. It will be simple and efficient. You may also want to limit the number of connections the server holds so that the limit is more is more predictable. </p>
<p>If you have to scale beyond one web server I suggest using something like Redis to keep track of which instance has a web socket connection to each user. </p></pre>Skylis: <pre><p>Benchmark your workload and see what's the best.</p>
<p>There are multiple ways to do it, and it depends on what you're doing which way will perform optimally.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传