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

在Go语言中,并发安全通常通过 sync 包来实现。该包提供了多种同步原语,帮助开发者在多个goroutine访问共享资源时避免竞态条件。以下是几种常见的使用方式和场景。
1. 使用 sync.Mutex 保护共享变量
当多个 goroutine 同时读写同一个变量时,需要使用互斥锁(Mutex)来确保同一时间只有一个 goroutine 能访问该资源。
示例:并发安全的计数器
立即学习“go语言免费学习笔记(深入)”;
package mainimport ("fmt""sync")
var counter intvar mu sync.Mutex
func increment(wg *sync.WaitGroup) {defer wg.Done()mu.Lock()counter++mu.Unlock()}
func main() {var wg sync.WaitGroupfor 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 mainimport ("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] = valuerwmu.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.WaitGroupfor 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 用于写操作,提升并发读性能。
3. 使用 sync.Once 实现单次初始化
某些初始化操作只需执行一次,例如加载配置、初始化连接池等。sync.Once 可保证函数只运行一次,即使被多个goroutine调用。
示例:单例模式初始化
package mainimport ("fmt""sync")
var instance *Servicevar 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.WaitGroupfor 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 mainimport ("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{"https://www.php.cn/link/0a16224c296f72af9037875a027f94a6","https://www.php.cn/link/6f942b9867c5426a14f5841ece172b18","https://www.php.cn/link/909c71100210781d37a568c5fc14e627",}
var wg sync.WaitGroupfor _, 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实现并发安全的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1416813.html
微信扫一扫
支付宝扫一扫