3 回答

TA貢獻1797條經驗 獲得超6個贊
如果我只考慮性能,是否有任何理由使用通道而不是互斥鎖?
不是真的。維基頁面“使用一個sync.Mutex
頻道還是一個頻道? ”說使用最有表現力和/或最簡單的那個。
有一個用于 Mutex 的通道示例,但正如評論的那樣:
雖然通道為受保護的數據提供了一個很好的解決方案,但在一個作者和多個讀者的情況下,它是一個效率較低的解決方案。
此線程添加:
如果您正在共享數據,并且從不阻塞鎖定部分,只需使用互斥鎖。
在非阻塞情況下,互斥量真的很便宜。如果您有一些共享服務執行復雜或冗長的操作,并且必須對其進行序列化,請考慮為其提供自己的 goroutine,該 goroutine 從通道接收請求并在完成后發回回復。通常你發送一個
struct
帶有輸入參數和一個用于回復的通道對象。
這很像 RPC。通道用于通信,而不是鎖定。
如果您僅出于鎖定目的通過通道發送無意義的數據,那么您可能會使事情變得過于復雜。

TA貢獻1820條經驗 獲得超9個贊
VonC 描述了您觀察到的結果背后的具體原因。在簡單的情況下,互斥體是高效的,因為它們是極簡主義的,而通道較少,因為還有很多工作要做,尤其是在將數據構造為Response
實例的示例代碼中。
您的測試程序很容易得出一個天真的結論,即互斥鎖就是您所需要的,共享內存就足夠了,而通道是一個浪費且不必要的好主意。那么為什么 Go 的創始人推薦通過通信來共享內存,而不是通過共享內存來通信呢?
并發不僅僅是鎖定共享數據。Communicating Sequential Processes (CSP) 背后的整個前提是,系統從根本上由進程(這里也稱為 goroutines)組成,這些進程通過事件的交換與彼此以及與外部世界進行交互,這些事件可能是攜帶信息的消息。這個模型是遞歸的:進程本身可能包含更小的進程來做事,通過事件的交換相互交互。
因此,Go 作為語言的關鍵部分所支持的通道通信模型是可擴展的??梢栽谛∫幠I厦枋霾l組件并使用組件來構建更大的組件,等等。您可以通過這種方式自然地描述高度并發的系統。
如果您嘗試僅使用互斥鎖來設計并發系統,您會感到沮喪并發現您必須編寫主要是順序的代碼。在某些情況下,最終的性能可能會更好,但在系統的表達能力和并行執行范圍方面可能會產生巨大的反成本。
如果您開始考慮如何保護共享數據免受競爭條件的影響,您將引導自己進入適合互斥鎖的設計,因為通道效率太低,因此沒有相關性。
多讀取器單寫入器共享數據的簡單情況經常出現,值得使用互斥鎖解決方案。但有時這可能意味著忽略基于具有多個客戶端的服務的更通用的解決方案。
最終,所有軟件設計都需要評估權衡并以一種或另一種方式做出決定。在 Go 中,您可以在適當的時候選擇使用通道和進程組合(即 goroutines)。很少有其他語言提供這一點。(奧卡姆是我所知道的唯一一個至少與圍棋一樣好)。
添加回答
舉報