面试题答案
一键面试问题根源分析
- 作用域问题:匿名函数在不同的goroutine中执行,虽然共享全局变量,但每个匿名函数有自己独立的执行上下文,可能会在不同时间点访问和修改全局变量,导致数据不一致。
- 资源竞争:多个goroutine同时读写全局变量,没有适当的同步机制,就会引发资源竞争问题。
优化方案
- 同步机制
- 互斥锁(Mutex):使用
sync.Mutex
来保护对全局变量的读写操作。在访问和修改全局变量前加锁,操作完成后解锁。 - 读写锁(RWMutex):如果读操作远多于写操作,可以使用
sync.RWMutex
。读操作时可以多个goroutine同时进行,写操作时则需要独占锁。
- 互斥锁(Mutex):使用
- 优化作用域设计
- 封装全局变量:将全局变量封装在一个结构体中,并提供方法来操作这些变量,在方法内部使用同步机制。
- 传递参数:尽量避免直接使用全局变量,而是将需要的数据作为参数传递给匿名函数,减少共享状态。
优化后的代码示例
package main
import (
"fmt"
"sync"
)
// 封装全局变量
type SharedData struct {
value int
mutex sync.Mutex
}
// 获取值的方法
func (sd *SharedData) Get() int {
sd.mutex.Lock()
defer sd.mutex.Unlock()
return sd.value
}
// 设置值的方法
func (sd *SharedData) Set(v int) {
sd.mutex.Lock()
defer sd.mutex.Unlock()
sd.value = v
}
func main() {
var wg sync.WaitGroup
sharedData := SharedData{}
// 模拟多个任务
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// 操作共享数据
sharedData.Set(id)
fmt.Printf("Goroutine %d set value to %d\n", id, sharedData.Get())
}(i)
}
wg.Wait()
}
在这个示例中,我们将全局变量封装在SharedData
结构体中,并使用sync.Mutex
来保护对value
的读写操作。每个匿名函数通过调用Set
和Get
方法来操作共享数据,从而避免了资源竞争和数据不一致的问题。