商城首页欢迎来到中国正版软件门户

您的位置:首页 >Golang sync并发安全实现方法

Golang sync并发安全实现方法

  发布于2025-12-07 阅读(0)

扫一扫,手机访问

Go语言中通过sync包实现并发安全,1. 使用sync.Mutex保护共享变量,如计数器示例防止数据竞争;2. 使用sync.RWMutex提升读多写少场景性能,允许多个读操作并发;3. 使用sync.Once确保初始化操作仅执行一次,适用于单例模式;4. 使用sync.WaitGroup等待所有goroutine完成,常用于任务协调。合理使用这些原语可避免竞态条件,提升程序稳定性与效率。

如何在Golang中使用sync实现并发安全

在Go语言中,并发安全通常通过 sync 包来实现。该包提供了多种同步原语,帮助开发者在多个goroutine访问共享资源时避免竞态条件。以下是几种常见的使用方式和场景。

1. 使用 sync.Mutex 保护共享变量

当多个 goroutine 同时读写同一个变量时,需要使用互斥锁(Mutex)来确保同一时间只有一个 goroutine 能访问该资源。

示例:并发安全的计数器

package main

import ( "fmt" "sync" )

var counter int var mu sync.Mutex

func increment(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() counter++ mu.Unlock() }

func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Counter:", counter) // 输出: Counter: 1000 }

说明:每次对 counter 的修改都包裹在 mu.Lock()mu.Unlock() 中,防止数据竞争。

2. 使用 sync.RWMutex 提高读性能

如果共享资源以读操作为主,可以使用读写锁 RWMutex。它允许多个读操作并发执行,但写操作独占锁。

示例:线程安全的配置存储

package main

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

var config = make(map[string]string) var rwmu sync.RWMutex

func readConfig(key string) string { rwmu.RLock() value := config[key] rwmu.RUnlock() return value }

func writeConfig(key, value string) { rwmu.Lock() config[key] = value rwmu.Unlock() }

func main() { go func() { for i := 0; i < 10; i++ { writeConfig("version", fmt.Sprintf("v%d", i)) time.Sleep(100 * time.Millisecond) } }()

var wg sync.WaitGroup
for i := 0; i &lt; 5; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        for j := 0; j &lt; 5; j++ {
            v := readConfig("version")
            fmt.Println("Read:", v)
            time.Sleep(50 * time.Millisecond)
        }
    }()
}
wg.Wait()

}

说明:RLock/RUnlock 用于读操作,Lock/Unlock 用于写操作,提升并发读性能。

3. 使用 sync.Once 实现单次初始化

某些初始化操作只需执行一次,例如加载配置、初始化连接池等。sync.Once 可保证函数只运行一次,即使被多个goroutine调用。

示例:单例模式初始化

package main

import ( "fmt" "sync" )

var instance *Service var once sync.Once

type Service struct { Data string }

func GetService() *Service { once.Do(func() { instance = &Service{Data: "Initialized"} fmt.Println("Service initialized") }) return instance }

func main() { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() s := GetService() fmt.Println(s.Data) }() } wg.Wait() }

输出中“Service initialized”只会打印一次。

4. 使用 sync.WaitGroup 等待 goroutine 完成

WaitGroup 用于主线程等待一组goroutine执行完毕,常用于并发任务协调。

示例:并发下载多个资源

package main

import ( "fmt" "sync" )

func download(url string, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("Downloading from", url) // 模拟耗时操作 // time.Sleep(time.Second) }

func main() { urls := []string{ "http://example.com/1", "http://example.com/2", "http://example.com/3", }

var wg sync.WaitGroup
for _, url := range urls {
    wg.Add(1)
    go download(url, &amp;wg)
}
wg.Wait()
fmt.Println("All downloads completed")

}

说明:每个 goroutine 开始前调用 Add(1),结束后调用 Done(),主线程通过 Wait() 阻塞直到全部完成。

基本上就这些常见用法。合理使用 sync 包中的工具,能有效避免数据竞争,实现安全高效的并发编程。注意不要过度加锁,避免死锁或性能下降。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注