面试题答案
一键面试- 使用
sync.Mutex
- 当方法涉及对共享数据的读写操作时,使用
sync.Mutex
来保护这些操作。 - 示例:
- 当方法涉及对共享数据的读写操作时,使用
type Counter struct {
value int
mu sync.Mutex
}
func (c *Counter) Increment() {
c.mu.Lock()
c.value++
c.mu.Unlock()
}
func (c *Counter) GetValue() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
- 使用
sync.RWMutex
- 如果读操作远多于写操作,可以使用
sync.RWMutex
。读操作时使用RLock
,写操作时使用Lock
。 - 示例:
- 如果读操作远多于写操作,可以使用
type Data struct {
data map[string]interface{}
rwmu sync.RWMutex
}
func (d *Data) Read(key string) interface{} {
d.rwmu.RLock()
defer d.rwmu.RUnlock()
return d.data[key]
}
func (d *Data) Write(key string, value interface{}) {
d.rwmu.Lock()
defer d.rwmu.Unlock()
if d.data == nil {
d.data = make(map[string]interface{})
}
d.data[key] = value
}
- 使用
sync.Cond
- 当需要在某个条件满足时唤醒等待的goroutine,可以使用
sync.Cond
。 - 示例:
- 当需要在某个条件满足时唤醒等待的goroutine,可以使用
type Queue struct {
data []interface{}
mu sync.Mutex
cond *sync.Cond
}
func NewQueue() *Queue {
q := &Queue{}
q.cond = sync.NewCond(&q.mu)
return q
}
func (q *Queue) Enqueue(item interface{}) {
q.mu.Lock()
q.data = append(q.data, item)
q.cond.Broadcast()
q.mu.Unlock()
}
func (q *Queue) Dequeue() interface{} {
q.mu.Lock()
for len(q.data) == 0 {
q.cond.Wait()
}
item := q.data[0]
q.data = q.data[1:]
q.mu.Unlock()
return item
}
- 设计方法结构适应并发环境
- 减少共享数据:尽量让每个goroutine有自己独立的数据,避免共享数据带来的竞争。例如,使用
context.Context
传递请求特定的数据,而不是在全局共享。 - 使用通道(Channel):通过通道进行goroutine间的通信和同步,避免直接共享数据。例如,设计一个生产者 - 消费者模型,生产者将数据发送到通道,消费者从通道接收数据。
- 减少共享数据:尽量让每个goroutine有自己独立的数据,避免共享数据带来的竞争。例如,使用
func producer(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) {
for value := range ch {
// 处理数据
}
}
- **分段锁**:对于大型数据结构,可以使用分段锁。例如,在一个大的哈希表中,为不同的哈希桶设置不同的锁,这样可以减少锁争用。
type ShardedMap struct {
shards []shard
}
type shard struct {
data map[string]interface{}
mu sync.Mutex
}
func NewShardedMap(numShards int) *ShardedMap {
sm := &ShardedMap{
shards: make([]shard, numShards),
}
for i := range sm.shards {
sm.shards[i].data = make(map[string]interface{})
}
return sm
}
func (sm *ShardedMap) Get(key string) interface{} {
index := int(hash(key)) % len(sm.shards)
sm.shards[index].mu.Lock()
defer sm.shards[index].mu.Unlock()
return sm.shards[index].data[key]
}
func (sm *ShardedMap) Set(key string, value interface{}) {
index := int(hash(key)) % len(sm.shards)
sm.shards[index].mu.Lock()
defer sm.shards[index].mu.Unlock()
sm.shards[index].data[key] = value
}
这里hash
函数是自定义的哈希函数,用于将键映射到合适的分片。