首页 >后端开发 >Golang >为什么互斥锁比 golang 中的通道慢?

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

王林
王林转载
2024-02-09 16:10:18751浏览

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

测试代码

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

解决方法

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

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

使用互斥体性能更好。

以上是为什么互斥锁比 golang 中的通道慢?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:stackoverflow.com。如有侵权,请联系admin@php.cn删除