Maison > Article > développement back-end > Pourquoi les mutex sont-ils plus lents que les canaux dans Golang ?
Pourquoi les mutex sont-ils plus lents que les canaux dans Golang ? Il s'agit d'un problème courant et de nombreux développeurs explorent la cause de ce problème. Les mutex et les canaux sont des mécanismes de synchronisation couramment utilisés dans Golang et jouent un rôle important dans la programmation simultanée. Cependant, nous constatons parfois que les performances des verrous mutex sont pires que celles des canaux. Pourquoi ? L'éditeur PHP Youzi répondra à cette question pour tout le monde dans cet article pour aider les lecteurs à mieux comprendre les différences de performances dans la programmation simultanée.
Je crée un programme qui explore les sites Web et renvoie leur statut.
J'ai écrit ce programme d'une manière différente. Le premier utilise un mutex pour empêcher les écritures simultanées sur la carte afin que je puisse me débarrasser des courses de données. Puis, dans le même but, je l'ai implémenté en utilisant des canaux. Mais lorsque je l'ai comparé, j'ai réalisé que l'implémenter à l'aide de canaux est beaucoup plus rapide que l'implémentation de mutex. Je veux savoir pourquoi cela arrive ? Pourquoi les mutex manquent-ils de performances ? Est-ce que je fais quelque chose de mal avec le mutex ?
Résultats du benchmark :
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 }
Code de test
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) } }
Il me semble qu'en utilisant une version mutuellement exclusive du code, vous protégez non seulement le fait que les appels à results
映射,还可以保护 wc
(只有在获得锁后才能进行调用,因此您可以有效地序列化调用)。仅当右侧准备好后,发送到 chan 才会锁定通道,因此对 wc
peuvent avoir lieu en même temps. Voyez si le code ressemble à
go func(u string) { defer wg.Done() r := wc(u) mu.Lock() results[u] = r mu.Unlock() }(url)
L'utilisation de mutex fonctionne mieux.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!