Heim >Backend-Entwicklung >Golang >Warum sind Mutexe langsamer als Kanäle in Golang?
Warum sind Mutexe langsamer als Kanäle in Golang? Dies ist ein häufiges Problem und viele Entwickler untersuchen die Ursache dieses Problems. Mutexe und Kanäle sind in Golang häufig verwendete Synchronisationsmechanismen und spielen eine wichtige Rolle bei der gleichzeitigen Programmierung. Manchmal stellen wir jedoch fest, dass die Leistung von Mutex-Sperren schlechter ist als die von Kanälen. Der PHP-Editor Youzi wird diese Frage in diesem Artikel für alle beantworten, um den Lesern zu helfen, die Leistungsunterschiede bei der gleichzeitigen Programmierung besser zu verstehen.
Ich erstelle ein Programm, das Websites crawlt und ihren Status zurückgibt.
Ich habe dieses Programm anders geschrieben. Der erste verwendet einen Mutex, um gleichzeitige Schreibvorgänge auf die Karte zu verhindern, sodass ich Datenrennen vermeiden kann. Dann habe ich es aus demselben Grund mithilfe von Kanälen implementiert. Aber als ich es einem Benchmarking unterzogen habe, wurde mir klar, dass die Implementierung mithilfe von Kanälen viel schneller ist als die Implementierung von Mutexes. Ich möchte wissen, warum das passiert? Warum mangelt es Mutexen an Leistung? Mache ich mit dem Mutex etwas falsch?
Benchmark-Ergebnisse:
Code
package concurrency import "sync" type websitechecker func(string) bool type result struct { string bool } func checkwebsites(wc websitechecker, urls []string) map[string]bool { results := make(map[string]bool) var wg sync.waitgroup var mu sync.mutex for _, url := range urls { wg.add(1) go func(u string) { defer wg.done() mu.lock() results[u] = wc(u) mu.unlock() }(url) } wg.wait() return results } func checkwebsiteschannel(wc websitechecker, urls []string) map[string]bool { results := make(map[string]bool) resultchannel := make(chan result) for _, url := range urls { go func(u string) { resultchannel <- result{u, wc(u)} }(url) } for i := 0; i < len(urls); i++ { r := <-resultchannel results[r.string] = r.bool } return results }
Testcode
package concurrency import ( "reflect" "testing" "time" ) func mockWebsiteChecker(url string) bool { time.Sleep(20 * time.Millisecond) if url == "https://localhost:3000" { return false } return true } func TestCheckWebsites(t *testing.T) { websites := []string{ "https://google.com", "https://localhost:3000", "https://blog.gypsydave5.com", } want := map[string]bool{ "https://google.com": true, "https://blog.gypsydave5.com": true, "https://localhost:3000": false, } got := CheckWebsites(mockWebsiteChecker, websites) if !reflect.DeepEqual(got, want) { t.Errorf("got %v, want %v", got, want) } } func BenchmarkCheckWebsites(b *testing.B) { urls := make([]string, 1000) for i := 0; i < len(urls); i++ { urls[i] = "a url" } b.ResetTimer() for i := 0; i < b.N; i++ { CheckWebsites(mockWebsiteChecker, urls) } } func BenchmarkCheckWebsitesChannel(b *testing.B) { urls := make([]string, 1000) for i := 0; i < len(urls); i++ { urls[i] = "a url" } b.ResetTimer() for i := 0; i < b.N; i++ { CheckWebsitesChannel(mockWebsiteChecker, urls) } }
Mir scheint, dass Sie durch die Verwendung einer sich gegenseitig ausschließenden Version des Codes nicht nur schützen, dass die Aufrufe von results
映射,还可以保护 wc
(只有在获得锁后才能进行调用,因此您可以有效地序列化调用)。仅当右侧准备好后,发送到 chan 才会锁定通道,因此对 wc
gleichzeitig erfolgen können. Sehen Sie, ob der Code so aussieht:
go func(u string) { defer wg.Done() r := wc(u) mu.Lock() results[u] = r mu.Unlock() }(url)
Die Verwendung von Mutexes führt zu einer besseren Leistung.
Das obige ist der detaillierte Inhalt vonWarum sind Mutexe langsamer als Kanäle in Golang?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!