Heim  >  Artikel  >  Backend-Entwicklung  >  Warum sind Mutexe langsamer als Kanäle in Golang?

Warum sind Mutexe langsamer als Kanäle in Golang?

王林
王林nach vorne
2024-02-09 16:10:18729Durchsuche

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

Frageninhalt

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

Workaround

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen