面试题答案
一键面试并发读写方面的考虑
- 互斥锁(Mutex):为了保护结构体数据在并发读写时不出现竞态条件,使用互斥锁来保证同一时间只有一个 goroutine 可以访问和修改结构体数据。
- 读写锁(RWMutex):如果读操作远多于写操作,可以使用读写锁。读操作可以并发进行,而写操作需要独占访问。
内存占用方面的考虑
- 合理字段布局:根据字段类型和对齐规则,合理安排结构体字段顺序,减少内存空洞,提高内存利用率。
- 避免不必要的嵌套:尽量减少不必要的嵌套层数,以降低内存碎片化的可能性。
数据一致性方面的考虑
- 事务处理:对于涉及多个数据修改的操作,要确保要么全部成功,要么全部失败,维持数据一致性。
- 版本控制:可以引入版本号机制,在读取数据时记录版本号,在写入时检查版本号,确保数据在读取后未被其他 goroutine 修改。
示例代码
package main
import (
"fmt"
"sync"
)
// 外层结构体
type Outer struct {
mu sync.RWMutex
inner Inner
}
// 内层结构体
type Inner struct {
data int
}
// 获取内层数据
func (o *Outer) GetInnerData() int {
o.mu.RLock()
defer o.mu.RUnlock()
return o.inner.data
}
// 设置内层数据
func (o *Outer) SetInnerData(newData int) {
o.mu.Lock()
defer o.mu.Unlock()
o.inner.data = newData
}
func main() {
var wg sync.WaitGroup
outer := Outer{}
// 启动多个 goroutine 进行并发读写
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
if id%2 == 0 {
outer.SetInnerData(id)
fmt.Printf("Goroutine %d set data to %d\n", id, id)
} else {
data := outer.GetInnerData()
fmt.Printf("Goroutine %d read data as %d\n", id, data)
}
}(i)
}
wg.Wait()
}
在上述代码中:
Outer
结构体包含一个sync.RWMutex
用于保护内部的Inner
结构体数据。GetInnerData
方法使用读锁(RLock
)来并发读取数据。SetInnerData
方法使用写锁(Lock
)来保证数据写入的原子性,避免并发写冲突。- 在
main
函数中,启动多个 goroutine 模拟并发读写操作。