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 ?

王林
王林avant
2024-02-09 16:10:18729parcourir

为什么互斥锁比 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.

Contenu de la question

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)
    }
}

Solution de contournement

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer