面试官:Go 有哪些方式安全读写共享变量

大家好,我是木川

Go 语言以其简洁、高效和并发性能而闻名。然而,在多个 goroutine 同时访问共享变量的情况下,可能会出现数据竞争和不确定的结果。

为了确保数据的一致性和正确性,Go 提供了多种方式来安全读写共享变量。本文将探讨几种常见的方法,并通过示例说明它们的用法。

一、不要修改变量

有时候,最安全的方式就是根本不修改共享变量。sync.Once 是一个很好的工具,用于确保某个函数只被执行一次,通常用于初始化全局变量。通过 sync.Once,可以在多个 goroutine 中安全地执行初始化操作,而无需担心竞争条件。

import (
 "fmt"
 "sync"
)

var sharedData int
var once sync.Once

func initializeSharedData() {
 sharedData = 42
}

func main() {
 for i := 0; i < 5; i++ {
  once.Do(initializeSharedData)
  fmt.Println(sharedData)
 }
}

在上面的示例中,initializeSharedData 函数只会执行一次,确保 sharedData 只被初始化一次,而后续的 goroutine 都可以安全地读取它。

二、只允许一个 goroutine 访问变量

使用通道是一种防止多个 goroutine 同时访问共享变量的方法,不要通过共享变量来通信,通过通信(channel)来共享变量。

通道是 Go 中并发编程的基础构建块,可以用于在不同 goroutine 之间传递数据,并确保同一时刻只有一个 goroutine 可以访问数据。

func main() {
 ch := make(chan int)

 go func() {
  ch <- 42 // 写入数据到通道
 }()

 x := <-ch // 从通道读取数据
 fmt.Println(x)
}

在上面的示例中,goroutine 将数据写入通道,然后主 goroutine 从通道读取数据。这确保了数据的顺序性和一致性。

三、允许多个 goroutine 访问变量,但是同一时间只允许一个 goroutine 访问

如果需要允许多个 goroutine 访问变量,实现锁机制,同时只有一个线程能拿到锁,需要互斥访问,可以使用互斥锁(Mutex)、读写锁(RWMutex)或原子操作。

sync.Mutex

sync.Mutex 是最基本的互斥锁,它确保在任何时候只有一个 goroutine 可以访问共享变量。

import (
 "fmt"
 "sync"
)

var mu sync.Mutex
var sharedData int

func main() {
 mu.Lock()
 sharedData = 42
 mu.Unlock()

 mu.Lock()
 x := sharedData
 mu.Unlock()

 fmt.Println(x)
}

sync.RWMutex

sync.RWMutex 支持多个 goroutine 同时读取共享数据,但只允许一个 goroutine 写入数据。这可以提高并发性能。

import (
 "fmt"
 "sync"
)

var mu sync.RWMutex
var sharedData int

func main() {
 mu.Lock()
 sharedData = 42 
 mu.Unlock()

 mu.RLock()
 x := sharedData
 mu.RUnlock()

 fmt.Println(x)
}

原子操作

sync/atomic 包提供了原子操作,可以安全地更新共享变量,这些操作是不可中断的。

import (
 "fmt"
 "sync/atomic"
)

var sharedData int32

func main() {
 atomic.StoreInt32(&sharedData, 42) // 原子存储
 x := atomic.LoadInt32(&sharedData)  // 原子加载

 fmt.Println(x)
}

通过上述方法,可以确保共享变量的安全读写,避免竞争条件和数据不一致性。

总之,Go 语言提供了多种方式来确保共享变量的安全读写,可以根据具体需求选择适当的方法。无论是使用 sync.Once 防止初始化问题,使用通道进行数据传递,还是使用互斥锁、读写锁或原子操作进行同步,都能帮助你编写出并发安全的 Go 代码。

最后给自己的原创 Go 面试小册打个广告,如果你从事 Go 相关开发,欢迎扫码购买,目前 10 元买断,加下面的微信发送支付截图额外赠送一份自己录制的 Go 面试题讲解视频

767e907110c9b230d56d2018ecfe0c9e.jpeg

30fe3d4e23ed87af464f8dcf077992b9.png

如果对你有帮助,帮我点一下在看或转发,欢迎关注我的公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值