3 回答

TA贡献1797条经验 获得超6个赞
如果我只考虑性能,是否有任何理由使用通道而不是互斥锁?
不是真的。维基页面“使用一个sync.Mutex
频道还是一个频道? ”说使用最有表现力和/或最简单的那个。
有一个用于 Mutex 的通道示例,但正如评论的那样:
虽然通道为受保护的数据提供了一个很好的解决方案,但在一个作者和多个读者的情况下,它是一个效率较低的解决方案。
此线程添加:
如果您正在共享数据,并且从不阻塞锁定部分,只需使用互斥锁。
在非阻塞情况下,互斥量真的很便宜。如果您有一些共享服务执行复杂或冗长的操作,并且必须对其进行序列化,请考虑为其提供自己的 goroutine,该 goroutine 从通道接收请求并在完成后发回回复。通常你发送一个
struct
带有输入参数和一个用于回复的通道对象。
这很像 RPC。通道用于通信,而不是锁定。
如果您仅出于锁定目的通过通道发送无意义的数据,那么您可能会使事情变得过于复杂。

TA贡献1820条经验 获得超9个赞
VonC 描述了您观察到的结果背后的具体原因。在简单的情况下,互斥体是高效的,因为它们是极简主义的,而通道较少,因为还有很多工作要做,尤其是在将数据构造为Response
实例的示例代码中。
您的测试程序很容易得出一个天真的结论,即互斥锁就是您所需要的,共享内存就足够了,而通道是一个浪费且不必要的好主意。那么为什么 Go 的创始人推荐通过通信来共享内存,而不是通过共享内存来通信呢?
并发不仅仅是锁定共享数据。Communicating Sequential Processes (CSP) 背后的整个前提是,系统从根本上由进程(这里也称为 goroutines)组成,这些进程通过事件的交换与彼此以及与外部世界进行交互,这些事件可能是携带信息的消息。这个模型是递归的:进程本身可能包含更小的进程来做事,通过事件的交换相互交互。
因此,Go 作为语言的关键部分所支持的通道通信模型是可扩展的。可以在小规模上描述并发组件并使用组件来构建更大的组件,等等。您可以通过这种方式自然地描述高度并发的系统。
如果您尝试仅使用互斥锁来设计并发系统,您会感到沮丧并发现您必须编写主要是顺序的代码。在某些情况下,最终的性能可能会更好,但在系统的表达能力和并行执行范围方面可能会产生巨大的反成本。
如果您开始考虑如何保护共享数据免受竞争条件的影响,您将引导自己进入适合互斥锁的设计,因为通道效率太低,因此没有相关性。
多读取器单写入器共享数据的简单情况经常出现,值得使用互斥锁解决方案。但有时这可能意味着忽略基于具有多个客户端的服务的更通用的解决方案。
最终,所有软件设计都需要评估权衡并以一种或另一种方式做出决定。在 Go 中,您可以在适当的时候选择使用通道和进程组合(即 goroutines)。很少有其他语言提供这一点。(奥卡姆是我所知道的唯一一个至少与围棋一样好)。
添加回答
举报