亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言中sync包使用方法教程

 更新時間:2025年03月29日 09:26:24   作者:Clown95  
在Go語言的并發(fā)編程實踐中,性能優(yōu)化總是繞不開的話題,下面這篇文章主要介紹了Go語言中sync包使用方法的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

Go 語言的 sync 包提供了基本的同步原語,用于在并發(fā)編程中協(xié)調(diào) goroutine 之間的操作。

1. 互斥鎖 (Mutex)

互斥鎖用于保護共享資源,確保同一時間只有一個 goroutine 可以訪問。

特點:

  • 最基本的同步原語,實現(xiàn)互斥訪問共享資源
  • 有兩個方法:Lock() 和 Unlock()
  • 不可重入,同一個 goroutine 重復獲取會導致死鎖
  • 沒有超時機制,鎖定后必須等待解鎖
  • 不區(qū)分讀寫操作,所有操作都是互斥的
  • 適用于共享資源競爭不激烈的場景
  • 性能高于 channel 實現(xiàn)的互斥機制
  • 不保證公平性,可能導致饑餓問題
import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var mutex sync.Mutex
    counter := 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            mutex.Lock()
            defer mutex.Unlock()
            counter++
        }()
    }
    
    time.Sleep(time.Second)
    fmt.Println("計數(shù)器:", counter)
}

2. 讀寫鎖 (RWMutex)

當多個 goroutine 需要讀取而很少寫入時,讀寫鎖比互斥鎖更高效。

特點:

  • 針對讀多寫少場景優(yōu)化的鎖
  • 提供四個方法:RLock()、RUnlock()Lock()、Unlock()
  • 允許多個讀操作并發(fā)進行,但寫操作是互斥的
  • 寫鎖定時,所有讀操作都會被阻塞
  • 有讀鎖定時,寫操作會等待所有讀操作完成
  • 寫操作優(yōu)先級較高,防止寫?zhàn)囸I
  • 內(nèi)部使用 Mutex 實現(xiàn)
  • 比 Mutex 有更多開銷,但在讀多寫少場景下性能更高
var rwMutex sync.RWMutex
var data map[string]string = make(map[string]string)

// 讀取操作
func read(key string) string {
    rwMutex.RLock()
    defer rwMutex.RUnlock()
    return data[key]
}

// 寫入操作
func write(key, value string) {
    rwMutex.Lock()
    defer rwMutex.Unlock()
    data[key] = value
}

3. 等待組 (WaitGroup)

等待組用于等待一組 goroutine 完成執(zhí)行。

特點:

  • 用于協(xié)調(diào)多個 goroutine 的完成
  • 提供三個方法:Add()、Done()Wait()
  • Add() 增加計數(shù)器,參數(shù)可為負數(shù)
  • Done() 等同于 Add(-1),減少計數(shù)器
  • Wait() 阻塞直到計數(shù)器歸零
  • 計數(shù)器不能變?yōu)樨摂?shù),會導致 panic
  • 可以重用,計數(shù)器歸零后可以再次增加
  • 非常適合"扇出"模式(啟動多個工作 goroutine 并等待全部完成)
  • 不包含工作內(nèi)容信息,僅表示完成狀態(tài)
  • 輕量級,開銷很小
func main() {
    var wg sync.WaitGroup
    
    for i := 0; i < 5; i++ {
        wg.Add(1) // 增加計數(shù)器
        go func(id int) {
            defer wg.Done() // 完成時減少計數(shù)器
            fmt.Printf("工作 %d 完成\n", id)
        }(i)
    }
    
    wg.Wait() // 等待所有 goroutine 完成
    fmt.Println("所有工作已完成")
}

4. 一次性執(zhí)行 (Once)

Once 確保一個函數(shù)只執(zhí)行一次,無論有多少 goroutine 嘗試執(zhí)行它。

特點:

  • 確保某個函數(shù)只執(zhí)行一次
  • 只有一個方法:Do(func())
  • 即使在多個 goroutine 中調(diào)用也只執(zhí)行一次
  • 常用于單例模式或一次性初始化
  • 內(nèi)部使用互斥鎖和一個標志位實現(xiàn)
  • 非常輕量級,幾乎沒有性能開銷
  • 如果傳入的函數(shù) panic,視為已執(zhí)行
  • 不能重置,一旦執(zhí)行就不能再次執(zhí)行
  • 傳入不同的函數(shù)也不會再次執(zhí)行
var once sync.Once
var instance *singleton

func getInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

5. 條件變量 (Cond)

條件變量用于等待或宣布事件的發(fā)生。

特點:

  • 用于等待或通知事件發(fā)生
  • 需要與互斥鎖結(jié)合使用:sync.NewCond(&mutex)
  • 提供三個方法:Wait()、Signal()、Broadcast()
  • Wait() 自動解鎖并阻塞,被喚醒后自動重新獲取鎖
  • Signal() 喚醒一個等待的 goroutine
  • Broadcast() 喚醒所有等待的 goroutine
  • 適合生產(chǎn)者-消費者模式
  • 可以避免輪詢,提高性能
  • 使用相對復雜,容易出錯
  • 等待必須在獲取鎖后調(diào)用
var mutex sync.Mutex
var cond = sync.NewCond(&mutex)
var ready bool

func main() {
    go producer()
    
    // 消費者
    mutex.Lock()
    for !ready {
        cond.Wait() // 等待條件變?yōu)檎?
    }
    fmt.Println("數(shù)據(jù)已準備好")
    mutex.Unlock()
}

func producer() {
    time.Sleep(time.Second) // 模擬工作
    
    mutex.Lock()
    ready = true
    cond.Signal() // 通知一個等待的 goroutine
    // 或使用 cond.Broadcast() 通知所有等待的 goroutine
    mutex.Unlock()
}

6. 原子操作 (atomic)

對于簡單的計數(shù)器或標志,可以使用原子操作包而不是互斥鎖。

特點:

  • 底層的原子操作,無鎖實現(xiàn)
  • 適用于簡單的計數(shù)器或標志位
  • 比互斥鎖性能更高,開銷更小
  • 提供多種原子操作:Add、LoadStore、SwapCompareAndSwap
  • 支持多種數(shù)據(jù)類型:int32、int64、uint32、uint64、uintptr 和指針
  • 可用于實現(xiàn)自己的同步原語
  • 不適合復雜的共享狀態(tài)
  • 在多 CPU 系統(tǒng)上可能導致緩存一致性開銷
  • Go 1.19 引入了新的原子類型
import (
    "fmt"
    "sync/atomic"
    "time"
)

func main() {
    var counter int64 = 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            atomic.AddInt64(&counter, 1)
        }()
    }
    
    time.Sleep(time.Second)
    fmt.Println("計數(shù)器:", atomic.LoadInt64(&counter))
}

7. Map (sync.Map)

Go 1.9 引入的線程安全的 map。

特點:

  • Go 1.9 引入的線程安全的哈希表
  • 無需額外加鎖即可安全地并發(fā)讀寫
  • 提供五個方法:Store、Load、LoadOrStore、Delete、Range
  • 內(nèi)部使用分段鎖和原子操作優(yōu)化性能
  • 適用于讀多寫少的場景
  • 不保證遍歷的順序
  • 不支持獲取元素數(shù)量或判斷是否為空
  • 不能像普通 map 那樣直接使用下標語法
  • 性能比加鎖的普通 map 更好,但單線程下比普通 map 慢
  • 內(nèi)存開銷較大
var m sync.Map

func main() {
    // 存儲鍵值對
    m.Store("key1", "value1")
    m.Store("key2", "value2")
    
    // 獲取值
    value, ok := m.Load("key1")
    if ok {
        fmt.Println("找到鍵:", value)
    }
    
    // 如果鍵不存在則存儲
    m.LoadOrStore("key3", "value3")
    
    // 刪除鍵
    m.Delete("key2")
    
    // 遍歷所有鍵值對
    m.Range(func(key, value interface{}) bool {
        fmt.Println(key, ":", value)
        return true // 返回 false 停止遍歷
    })
}

8. Pool (sync.Pool)

對象池用于重用臨時對象,減少垃圾回收壓力。

特點:

  • 用于緩存臨時對象,減少垃圾回收壓力
  • 提供兩個方法:Get() 和 Put()
  • 需要提供 New 函數(shù)來創(chuàng)建新對象
  • 對象可能在任何時候被垃圾回收,不保證存活
  • 在 GC 發(fā)生時會清空池中的所有對象
  • 不適合管理需要顯式關閉的資源(如文件句柄)
  • 適合于頻繁創(chuàng)建和銷毀的對象
  • 沒有大小限制,Put 總是成功的
  • 每個 P(處理器)有自己的本地池,減少競爭
  • Go 1.13 后大幅提升了性能
var bufferPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func process() {
    // 獲取緩沖區(qū)
    buffer := bufferPool.Get().(*bytes.Buffer)
    buffer.Reset() // 清空以便重用
    
    // 使用緩沖區(qū)
    buffer.WriteString("hello")
    
    // 操作完成后放回池中
    bufferPool.Put(buffer)
}

9. 綜合示例

下面是一個綜合示例,展示了多個同步原語的使用:

package main

import (
    "fmt"
    "sync"
    "time"
)

type SafeCounter struct {
    mu sync.Mutex
    wg sync.WaitGroup
    count int
}

func main() {
    counter := SafeCounter{}
    
    // 啟動 5 個 goroutine 增加計數(shù)器
    for i := 0; i < 5; i++ {
        counter.wg.Add(1)
        go func(id int) {
            defer counter.wg.Done()
            
            for j := 0; j < 10; j++ {
                counter.mu.Lock()
                counter.count++
                fmt.Printf("Goroutine %d: 計數(shù)器 = %d\n", id, counter.count)
                counter.mu.Unlock()
                
                // 模擬工作
                time.Sleep(100 * time.Millisecond)
            }
        }(i)
    }
    
    // 等待所有 goroutine 完成
    counter.wg.Wait()
    fmt.Println("最終計數(shù):", counter.count)
}

最佳實踐

  • 使用 defer 解鎖:確保即使發(fā)生錯誤也能解鎖

    mu.Lock()
    defer mu.Unlock()
    
  • 避免鎖的嵌套:容易導致死鎖

  • 保持臨界區(qū)簡短:鎖定時間越短越好

  • 基準測試比較

    • 對于大多數(shù)簡單操作,atomic 比 Mutex 快
    • RWMutex 在讀操作遠多于寫操作時優(yōu)于 Mutex
    • sync.Map 在高并發(fā)下比加鎖的 map 性能更好
  • 內(nèi)存對齊

    • 原子操作需要內(nèi)存對齊
    • 不正確的內(nèi)存對齊會嚴重影響性能
    • 特別是在 32 位系統(tǒng)上使用 64 位原子操作
  • 超時控制

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    done := make(chan struct{})
    go func() {
        // 執(zhí)行可能耗時的操作
        mu.Lock()
        // ...
        mu.Unlock()
        
        done <- struct{}{}
    }()
    
    select {
    case <-done:
        // 操作成功完成
    case <-ctx.Done():
        // 操作超時
    }

總結(jié) 

到此這篇關于Go語言中sync包使用方法的文章就介紹到這了,更多相關Go語言sync包使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Kotlin編程基礎語法編碼規(guī)范

    Kotlin編程基礎語法編碼規(guī)范

    這篇文章主要為大家介紹了Kotlin編程條件控制示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 使用Go語言開發(fā)一個高并發(fā)系統(tǒng)

    使用Go語言開發(fā)一個高并發(fā)系統(tǒng)

    高并發(fā)系統(tǒng)是指能同時支持眾多用戶請求,處理大量并行計算的系統(tǒng),這篇文章主要為大家詳細介紹了如何使用Go語言開發(fā)一個高并發(fā)系統(tǒng),感興趣的小伙伴可以了解下
    2023-11-11
  • 一百行Golang代碼實現(xiàn)簡單并發(fā)聊天室

    一百行Golang代碼實現(xiàn)簡單并發(fā)聊天室

    這篇文章主要為大家詳細介紹了一百行Golang代碼如何實現(xiàn)簡單并發(fā)聊天室,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 一文吃透Go的內(nèi)置RPC原理

    一文吃透Go的內(nèi)置RPC原理

    這篇文章主要為大家詳細介紹了Go語言中內(nèi)置RPC的原理。說起?RPC?大家想到的一般是框架,Go?作為編程語言竟然還內(nèi)置了?RPC,著實讓我有些吃鯨,本文就來一起聊聊吧
    2023-03-03
  • go語言實現(xiàn)猜數(shù)字小游戲的方法

    go語言實現(xiàn)猜數(shù)字小游戲的方法

    這篇文章主要介紹了go語言實現(xiàn)猜數(shù)字小游戲的方法,實例分析了Go語言流程判斷與處理的技巧,需要的朋友可以參考下
    2015-03-03
  • golang如何去除多余空白字符(含制表符)

    golang如何去除多余空白字符(含制表符)

    這篇文章主要介紹了golang去除多余空白字符(含制表符)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • go使用snmp庫查詢mib數(shù)據(jù)案例代碼

    go使用snmp庫查詢mib數(shù)據(jù)案例代碼

    go語言使用snmp庫中的 k-sone/snmpgo 實現(xiàn)相關mib查詢,本文通過實例代碼給大家介紹了go使用snmp庫查詢mib數(shù)據(jù),感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • go語言中gorm時間格式化

    go語言中gorm時間格式化

    本文主要介紹了go語言中gorm時間格式化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • 淺析Go語言版本的forgery

    淺析Go語言版本的forgery

    使用過Python語言的朋友們可能使用過 forgery_py ,它是一個偽造數(shù)據(jù)的工具。這篇文章主要介紹了Go語言版本的forgery,需要的朋友可以參考下
    2018-08-08
  • golang中接口對象的轉(zhuǎn)型兩種方式

    golang中接口對象的轉(zhuǎn)型兩種方式

    這篇文章主要介紹了golang中接口對象的轉(zhuǎn)型方式,大家都知道接口對象的轉(zhuǎn)型有兩種方式,文中通過示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2021-10-10

最新評論