我有几个我希望它们原子执行的函数,因为它们处理敏感的数据结构。假设以下情况:
有两个函数:lock(sth)unlock(sth),可以通过goroutine随时调用以锁定或解锁全局数组中的sth。我正在考虑建立一个命令通道,以便goroutines将lockunlock命令发送到该通道中,并且在该通道的接收端,某种handler依次处理lockunlock请求,通过从渠道抓取命令。很好,但是如果handler想要将结果发送回请求者怎么办?可以使用golang频道吗?我知道可以使用诸如互斥锁之类的锁定机制,但是我想知道是否可以在这种用例中使用通道?我在某处看到建议使用channel而不是goland低级锁定结构。

用一句话:

我希望在容量为1的通道中,接收方能够回复发送消息的goroutine。

或等效地:

goroutine将某些内容发送到通道;该消息被另一个goroutine接收并进行处理,从而导致某些结果;发件人如何得知结果?

sync软件包包括互斥锁sync.Mutex,可以通过任何goroutine以线程安全的方式对其进行锁定和解锁。与其使用通道发送命令来锁定某些内容,不如仅使用发送者的互斥锁?

当您说发送方如何得知结果时,我认为您是在谈论处理程序如何接收结果-就是chan。您可以通过通道发送数据。

另外,如果您只是想知道,信号量sync.WaitGroup可能会起作用。可以将此结构Add()绑定到,然后发送方可以wg.Wait()直到处理程序调用wg.Done(),这将向发送方(正在等待)指示处理程序已完成此操作。

如果您的问题是关于使用锁还是通道,那么Wiki有一个简洁的答案:

A common Go newbie mistake is to over-use channels and goroutines just because it's possible, and/or because it's fun. Don't be afraid to use a sync.Mutex if that fits your problem best. Go is pragmatic in letting you use the tools that solve your problem best and not forcing you into one style of code.

As a general guide, though:

Channel: passing ownership of data, distributing units of work, communicating async results
Mutex: caches, state

如果您绝对要避免使用chan s :)以外的内容,请尝试不要更改敏感数组。而是使用通道将数据发送到不同的goroutine,在每一步处理数据,然后将处理后的数据集中到最终类型的goroutine中。也就是说,完全避免使用数组并将数据存储在chan中。

座右铭是

Do not communicate by sharing memory; instead, share memory by communicating.

如果要防止争用情况,则sync原语应该可以正常工作,如@Nevermore的答案所述。它使代码更具可读性,并且更易于推理。

但是,如果您希望频道为您执行同步,则可以随时尝试以下操作:

要使用此Operate,请传递一个访问受保护资源的闭包。

工作示例:https://play.golang.org/p/Drh-yJDVNh

或者,您可以完全绕过Operate并直接使用lock来提高可读性:

工作示例:https://play.golang.org/p/me3K6aIoR7

如您所见,arr访问在此处使用通道进行保护。

其他问题已经很好地涵盖了锁定,但是我想解决有关使用通道将响应发送回呼叫者的问题的另一部分。 Go中有一种不常见的模式,即与请求一起发送响应通道。例如,您可能通过通道将命令发送给处理程序;这些命令将是具有特定于实现的详细信息的struct,并且该结构将包括用于将结果发送回并键入为结果类型的通道。发送的每个命令都将包含一个新通道,处理程序将使用该通道发送回响应,然后关闭。为了显示: