Mengapakah mutex lebih perlahan daripada saluran dalam golang?

王林
Lepaskan: 2024-02-09 16:10:18
ke hadapan
733 orang telah melayarinya

为什么互斥锁比 golang 中的通道慢?

为什么互斥锁比 golang 中的通道慢?这是一个常见的问题,许多开发者都在探索这个问题的原因。互斥锁和通道是 golang 中常用的同步机制,它们在并发编程中起着重要的作用。然而,有时我们会发现互斥锁的性能比通道差,这是为什么呢?php小编柚子将在本文中为大家解答这个问题,帮助读者更好地理解并发编程中的性能差异。

问题内容

我正在制作一个程序来抓取网站并返回它们的状态。

我用不同的方法编写了这个程序。第一个使用互斥体来防止并发写入映射,以便我可以摆脱数据竞争。然后出于同样的目的,我用渠道来实现它。但是当我进行基准测试时,我意识到使用通道实现它比实现互斥体要快得多。我想知道为什么会发生这种情况?为什么互斥体缺乏性能?我对互斥体做错了什么吗?

基准结果:

代码

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
}
Salin selepas log masuk

测试代码

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)
    }
}
Salin selepas log masuk

解决方法

在我看来,使用互斥版本的代码,您不仅可以保护 results 映射,还可以保护 wc (只有在获得锁后才能进行调用,因此您可以有效地序列化调用)。仅当右侧准备好后,发送到 chan 才会锁定通道,因此对 wc 的调用可以同时发生。看看代码是否像

        go func(u string) {
            defer wg.Done()
            r := wc(u)
            mu.Lock()
            results[u] = r
            mu.Unlock()
        }(url)
Salin selepas log masuk

使用互斥体性能更好。

Atas ialah kandungan terperinci Mengapakah mutex lebih perlahan daripada saluran dalam golang?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:stackoverflow.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan