在几个不同的 goroutine 之间共享一个切片
Sharing a slice across a few different goroutines
鉴于我有一片 User 类型的结构
Users := make([]User)
我正在侦听 TCP 连接,当有用户连接时,我会向此切片添加一个新用户。
我这样做的方法是设置一个 NewUsers 频道
NewUsers := make(chan User)
在新的 TCP 连接时,一个用户被发送到这个通道,一个中央函数等待一个用户到达以将其添加到用户切片。
但现在我想要多个子系统 (packages/functions) 使用这个用户列表。一个函数可能只想接收用户列表,而另一个函数可能想要向每个用户广播消息,或者只向符合特定条件的用户广播消息。
多个函数(可能从不同的 goroutines 执行)如何安全地访问用户列表。我看到两种可能的方式:
- 需要访问此列表的每个子系统都需要自己的 AddUser 频道并维护自己的用户片段,并且需要将新用户广播到这些频道中的每一个频道。
- 使用 Mutex 阻止访问
选项 1 似乎非常复杂并且会产生相当多的重复,但我的理解是如果您尝试坚持 "Share Memory By Communicating" 咒语,最好避免使用互斥锁。
互斥方法是解决该问题的最佳、最安全和最易于管理的方法,也是最快的方法。
通道在内部是复杂的野兽,比受保护的 rwmutex 慢得多 map/slice。
在并发活动之间共享数据的惯用 Go 方式总结如下:
Do not communicate by sharing memory; instead, share memory by
communicating.
安德鲁·杰朗 blogged about this,例如。
不需要太复杂;你可以考虑设计内部微服务,使用带有通道的 goroutines 来表达。
对于您的情况,这可能意味着设计一个服务元素以包含用户列表的主副本。
Go/CSP 策略的主要优势在于
- 并发性是一种设计选择,以及您设计的其他方面
- 只需要本地知识来理解并发行为:这是因为 goroutine 本身可以由内部 goroutine 组成,如果需要,这会一直适用。了解更高级别 goroutine 的外部行为仅取决于其接口,而不取决于隐藏的内部结构。
但是...
有时安全共享的数据结构(受互斥锁保护)现在和永远都足够了。然后可能会争辩说 goroutines 和通道的额外复杂性不是必需的。
您会发现许多人已将安全共享列表数据结构作为开源 API 提供。 (我自己有一个 - 请参阅 runtemplate 中的内置插件)。
鉴于我有一片 User 类型的结构
Users := make([]User)
我正在侦听 TCP 连接,当有用户连接时,我会向此切片添加一个新用户。
我这样做的方法是设置一个 NewUsers 频道
NewUsers := make(chan User)
在新的 TCP 连接时,一个用户被发送到这个通道,一个中央函数等待一个用户到达以将其添加到用户切片。
但现在我想要多个子系统 (packages/functions) 使用这个用户列表。一个函数可能只想接收用户列表,而另一个函数可能想要向每个用户广播消息,或者只向符合特定条件的用户广播消息。
多个函数(可能从不同的 goroutines 执行)如何安全地访问用户列表。我看到两种可能的方式:
- 需要访问此列表的每个子系统都需要自己的 AddUser 频道并维护自己的用户片段,并且需要将新用户广播到这些频道中的每一个频道。
- 使用 Mutex 阻止访问
选项 1 似乎非常复杂并且会产生相当多的重复,但我的理解是如果您尝试坚持 "Share Memory By Communicating" 咒语,最好避免使用互斥锁。
互斥方法是解决该问题的最佳、最安全和最易于管理的方法,也是最快的方法。
通道在内部是复杂的野兽,比受保护的 rwmutex 慢得多 map/slice。
在并发活动之间共享数据的惯用 Go 方式总结如下:
Do not communicate by sharing memory; instead, share memory by communicating.
安德鲁·杰朗 blogged about this,例如。
不需要太复杂;你可以考虑设计内部微服务,使用带有通道的 goroutines 来表达。
对于您的情况,这可能意味着设计一个服务元素以包含用户列表的主副本。
Go/CSP 策略的主要优势在于
- 并发性是一种设计选择,以及您设计的其他方面
- 只需要本地知识来理解并发行为:这是因为 goroutine 本身可以由内部 goroutine 组成,如果需要,这会一直适用。了解更高级别 goroutine 的外部行为仅取决于其接口,而不取决于隐藏的内部结构。
但是...
有时安全共享的数据结构(受互斥锁保护)现在和永远都足够了。然后可能会争辩说 goroutines 和通道的额外复杂性不是必需的。
您会发现许多人已将安全共享列表数据结构作为开源 API 提供。 (我自己有一个 - 请参阅 runtemplate 中的内置插件)。