在几个不同的goroutine上分享切片

时间:2016-07-10 04:04:44

标签: go goroutine

鉴于我有一个User

类型的结构
Users := make([]User)

我正在侦听TCP连接,当用户连接时,我正在为此切片添加新用户。

我这样做的方法是设置一个NewUsers频道

NewUsers := make(chan User)

当新的TCP连接时,用户会被发送到此频道,并且中央功能会等待用户到达以将其添加到用户切片。

但是现在我想要多个子系统(包/函数)来使用这个用户列表。一个功能可能只是想要接收用户列表,而另一个功能可能想要向每个用户广播消息,或者只是想要匹配某个条件的用户。

多个功能(可能从不同的goroutine执行)如何安全地访问用户列表。我看到两种可能的方式:

  1. 每个需要访问此列表的子系统都需要自己的AddUser频道并维护自己的用户片段,并且需要向这些频道中的每个频道广播新用户。
  2. 使用互斥锁阻止访问
  3. 选项1似乎非常复杂,会产生相当多的重复,但我的理解是,如果你试图坚持“通过沟通共享记忆”的口头禅,最好避免互斥。

2 个答案:

答案 0 :(得分:2)

互斥方法是解决该问题的最佳,最安全,最易管理的方法,也是最快的方法。

通道内部是复杂的野兽,比rwmutex保护的地图/切片要慢得多。

答案 1 :(得分:2)

在并发活动之间共享数据的惯用Go方法总结如下:

  

不要通过共享内存进行通信;相反,分享记忆   连通。

Andrew Gerrand blogged about this,例如。

它不必过于复杂;您可以考虑设计内部微服务,使用带有通道的goroutine表示。

在您的情况下,这可能意味着设计一个服务元素以包含用户列表的主副本。

Go / CSP策略的主要优点是

  • 并发是一种设计选择,以及您设计的其他方面
  • 只需要本地知识来理解并发行为:这是因为goroutine本身可以由内部goroutine组成,并且如果需要,它会一直向下。了解更高级别goroutine的外部行为仅取决于其接口,而不取决于隐藏的内部。

<强>可是...

有时,安全共享数据结构(受互斥锁保护)现在和将来都足够了。然后可能会认为goroutines和渠道的额外复杂性是不需要的。

安全共享列表数据结构是您可以找到的几个人作为开源API提供的结构。 (我自己有一个 - 见runtemplate中的内置插件)。