亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang,如何共享價值——消息還是互斥?

Golang,如何共享價值——消息還是互斥?

守候你守候我 2021-08-23 17:12:26
我已經完成了簡單的基準測試,在消息傳遞和共享值鎖定中哪一個更有效。首先,請檢查下面的代碼。package mainimport (    "flag"    "fmt"    "math/rand"    "runtime"    "sync"    "time")type Request struct {    Id      int    ResChan chan Response}type Response struct {    Id    int    Value int}func main() {    procNum := flag.Int("proc", 1, "Number of processes to use")    clientNum := flag.Int("client", 1, "Number of clients")    mode := flag.String("mode", "message", "message or mutex")    flag.Parse()    if *procNum > runtime.NumCPU() {        *procNum = runtime.NumCPU()    }    fmt.Println("proc:", *procNum)    fmt.Println("client:", *clientNum)    fmt.Println("mode:", *mode)    runtime.GOMAXPROCS(*procNum)    rand.Seed(time.Now().UnixNano())    var wg sync.WaitGroup    sharedValue := 0    start := time.Now()    if *mode == "message" {        reqChan := make(chan Request) // increasing channel size does not change the result        go func() {            for {                req := <-reqChan                sharedValue++                req.ResChan <- Response{Id: req.Id, Value: sharedValue}            }        }()        for i := 0; i < *clientNum; i++ {            wg.Add(1)            go func(index int) {                defer wg.Done()                c := make(chan Response)                defer close(c)                id := rand.Int()                reqChan <- Request{Id: id, ResChan: c}                <-c            }(i)        }    } else if *mode == "mutex" {        mutex := &sync.Mutex{}        for i := 0; i < *clientNum; i++ {            wg.Add(1)            go func(index int) {                defer wg.Done()                mutex.Lock()                sharedValue++                mutex.Unlock()            }(i)        }    }正如您已經注意到的,程序相對簡單。在消息模式下,它通過消息傳遞增加 sharedValue。在互斥模式下,它通過鎖定來增加sharedValue。我曾嘗試僅使用一個通道進行消息模式并放棄了。我想這可能是不可能的,不是嗎?我的電腦有 2 個 Xeon CPU,每個 CPU 有 6 個內核。由于超線程,邏輯上有 24 個內核可用。其內存大小為 12G。如果我使用任意數量的標志運行程序,互斥模式總是至少快 2 倍(通常是 3 倍)。好的,我可以理解管理渠道需要一定的成本。那么,如果我只考慮性能,是否有任何理由使用通道而不是互斥鎖?另外,消息傳遞的成本是否可以被巨大的消息忽略?
查看完整描述

3 回答

?
FFIVE

TA貢獻1797條經驗 獲得超6個贊

如果我只考慮性能,是否有任何理由使用通道而不是互斥鎖?

不是真的。維基頁面“使用一個sync.Mutex頻道還是一個頻道? ”說使用最有表現力和/或最簡單的那個。
有一個用于 Mutex 的通道示例,但正如評論的那樣:

雖然通道為受保護的數據提供了一個很好的解決方案,但在一個作者和多個讀者的情況下,它是一個效率較低的解決方案。

此線程添加:

如果您正在共享數據,并且從不阻塞鎖定部分,只需使用互斥鎖。
在非阻塞情況下,互斥量真的很便宜。

如果您有一些共享服務執行復雜或冗長的操作,并且必須對其進行序列化,請考慮為其提供自己的 goroutine,該 goroutine 從通道接收請求并在完成后發回回復。通常你發送一個struct帶有輸入參數和一個用于回復的通道對象。
這很像 RPC。

通道用于通信,而不是鎖定。
如果您僅出于鎖定目的通過通道發送無意義的數據,那么您可能會使事情變得過于復雜。


查看完整回答
反對 回復 2021-08-23
?
慕妹3146593

TA貢獻1820條經驗 獲得超9個贊

VonC 描述了您觀察到的結果背后的具體原因。在簡單的情況下,互斥體是高效的,因為它們是極簡主義的,而通道較少,因為還有很多工作要做,尤其是在將數據構造為Response實例的示例代碼中。

您的測試程序很容易得出一個天真的結論,即互斥鎖就是您所需要的,共享內存就足夠了,而通道是一個浪費且不必要的好主意。那么為什么 Go 的創始人推薦通過通信來共享內存,而不是通過共享內存來通信呢?

并發不僅僅是鎖定共享數據。Communicating Sequential Processes (CSP) 背后的整個前提是,系統從根本上由進程(這里也稱為 goroutines)組成,這些進程通過事件的交換與彼此以及與外部世界進行交互,這些事件可能是攜帶信息的消息。這個模型是遞歸的:進程本身可能包含更小的進程來做事,通過事件的交換相互交互。

因此,Go 作為語言的關鍵部分所支持的通道通信模型是可擴展的??梢栽谛∫幠I厦枋霾l組件并使用組件來構建更大的組件,等等。您可以通過這種方式自然地描述高度并發的系統。

如果您嘗試僅使用互斥鎖來設計并發系統,您會感到沮喪并發現您必須編寫主要是順序的代碼。在某些情況下,最終的性能可能會更好,但在系統的表達能力和并行執行范圍方面可能會產生巨大的反成本。

如果您開始考慮如何保護共享數據免受競爭條件的影響,您將引導自己進入適合互斥鎖的設計,因為通道效率太低,因此沒有相關性。

多讀取器單寫入器共享數據的簡單情況經常出現,值得使用互斥鎖解決方案。但有時這可能意味著忽略基于具有多個客戶端的服務的更通用的解決方案。

最終,所有軟件設計都需要評估權衡并以一種或另一種方式做出決定。在 Go 中,您可以在適當的時候選擇使用通道和進程組合(即 goroutines)。很少有其他語言提供這一點。(奧卡姆是我所知道的唯一一個至少與圍棋一樣好)。


查看完整回答
反對 回復 2021-08-23
  • 3 回答
  • 0 關注
  • 159 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號