首頁  >  文章  >  後端開發  >  為什麼互斥鎖比 golang 中的頻道慢?

為什麼互斥鎖比 golang 中的頻道慢?

王林
王林轉載
2024-02-09 16:10:18682瀏覽

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