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

在Go语言中,并发安全通常通过 sync 包来实现。该包提供了多种同步原语,帮助开发者在多个goroutine访问共享资源时避免竞态条件。以下是几种常见的使用方式和场景。
当多个 goroutine 同时读写同一个变量时,需要使用互斥锁(Mutex)来确保同一时间只有一个 goroutine 能访问该资源。
示例:并发安全的计数器
立即学习“go语言免费学习笔记(深入)”;
package main
<p>import (
"fmt"
"sync"
)</p><p>var counter int
var mu sync.Mutex</p><p>func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}</p><p>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() 中,防止数据竞争。
如果共享资源以读操作为主,可以使用读写锁 RWMutex。它允许多个读操作并发执行,但写操作独占锁。
示例:线程安全的配置存储
package main
<p>import (
"fmt"
"sync"
"time"
)</p><p>var config = make(map[string]string)
var rwmu sync.RWMutex</p><p>func readConfig(key string) string {
rwmu.RLock()
value := config[key]
rwmu.RUnlock()
return value
}</p><p>func writeConfig(key, value string) {
rwmu.Lock()
config[key] = value
rwmu.Unlock()
}</p><p>func main() {
go func() {
for i := 0; i < 10; i++ {
writeConfig("version", fmt.Sprintf("v%d", i))
time.Sleep(100 * time.Millisecond)
}
}()</p><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 5; j++ {
v := readConfig("version")
fmt.Println("Read:", v)
time.Sleep(50 * time.Millisecond)
}
}()
}
wg.Wait()}
说明:RLock/RUnlock 用于读操作,Lock/Unlock 用于写操作,提升并发读性能。
一个类似淘宝助理、ebay助理的客户端程序,用来方便的在本地处理商店数据,并能够在本地商店、网上商店和第三方平台之间实现数据上传下载功能的工具。功能说明如下:1.连接本地商店:您可以使用ShopEx助理连接一个本地安装的商店系统,这样就可以使用助理对本地商店的商品数据进行编辑等操作,并且数据也将存放在本地商店数据库中。默认是选择“本地未安装商店”,本地还未安
0
某些初始化操作只需执行一次,例如加载配置、初始化连接池等。sync.Once 可保证函数只运行一次,即使被多个goroutine调用。
示例:单例模式初始化
package main
<p>import (
"fmt"
"sync"
)</p><p>var instance *Service
var once sync.Once</p><p>type Service struct {
Data string
}</p><p>func GetService() *Service {
once.Do(func() {
instance = &Service{Data: "Initialized"}
fmt.Println("Service initialized")
})
return instance
}</p><p>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”只会打印一次。
WaitGroup 用于主线程等待一组goroutine执行完毕,常用于并发任务协调。
示例:并发下载多个资源
package main
<p>import (
"fmt"
"sync"
)</p><p>func download(url string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("Downloading from", url)
// 模拟耗时操作
// time.Sleep(time.Second)
}</p><p>func main() {
urls := []string{
"<a href="https://www.php.cn/link/0a16224c296f72af9037875a027f94a6">https://www.php.cn/link/0a16224c296f72af9037875a027f94a6</a>",
"<a href="https://www.php.cn/link/6f942b9867c5426a14f5841ece172b18">https://www.php.cn/link/6f942b9867c5426a14f5841ece172b18</a>",
"<a href="https://www.php.cn/link/909c71100210781d37a568c5fc14e627">https://www.php.cn/link/909c71100210781d37a568c5fc14e627</a>",
}</p><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go download(url, &wg)
}
wg.Wait()
fmt.Println("All downloads completed")}
说明:每个 goroutine 开始前调用 Add(1),结束后调用 Done(),主线程通过 Wait() 阻塞直到全部完成。
基本上就这些常见用法。合理使用 sync 包中的工具,能有效避免数据竞争,实现安全高效的并发编程。注意不要过度加锁,避免死锁或性能下降。
以上就是如何在Golang中使用sync实现并发安全的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号