MST

星途 面试题库

面试题:Go生成器性能调优之资源竞争处理

假设在一个并发环境下,多个协程会同时调用一个Go生成器获取数据,在此过程中出现了性能问题,经分析是资源竞争导致的。阐述你会采取哪些策略和方法来解决这个资源竞争问题,从而优化生成器的性能,并举例说明如何使用相关的同步原语。
42.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

解决策略和方法

  1. 互斥锁(Mutex)
    • 原理:互斥锁用于保护共享资源,同一时间只有一个协程可以获取锁并访问共享资源,其他协程需要等待锁被释放。
    • 应用场景:适用于对共享资源读写操作都可能发生资源竞争的情况。
  2. 读写锁(RWMutex)
    • 原理:读写锁区分了读操作和写操作。多个协程可以同时进行读操作,但写操作时需要独占锁,以防止读 - 写、写 - 写冲突。
    • 应用场景:适用于读操作远多于写操作的场景,这样可以提高并发读的效率。
  3. 通道(Channel)
    • 原理:通道用于在协程之间传递数据,它本身是线程安全的。通过通道传递数据可以避免共享资源的竞争。
    • 应用场景:适用于将数据生成和数据消费分离,通过通道来传递数据。
  4. 原子操作(Atomic Operations)
    • 原理:原子操作是不可分割的操作,在执行过程中不会被其他操作打断,Go标准库提供了原子操作的支持。
    • 应用场景:适用于对简单数据类型(如整数)的操作,避免使用锁带来的开销。

同步原语使用示例

  1. 互斥锁示例
package main

import (
    "fmt"
    "sync"
)

var (
    mu    sync.Mutex
    count int
)

func generator(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.Lock()
    count++
    fmt.Printf("Generator incremented count to %d\n", count)
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go generator(&wg)
    }
    wg.Wait()
}
  1. 读写锁示例
package main

import (
    "fmt"
    "sync"
)

var (
    rwmu  sync.RWMutex
    value int
)

func reader(wg *sync.WaitGroup) {
    defer wg.Done()
    rwmu.RLock()
    fmt.Printf("Reader read value: %d\n", value)
    rwmu.RUnlock()
}

func writer(wg *sync.WaitGroup) {
    defer wg.Done()
    rwmu.Lock()
    value++
    fmt.Printf("Writer incremented value to %d\n", value)
    rwmu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go reader(&wg)
    }
    for i := 0; i < 2; i++ {
        wg.Add(1)
        go writer(&wg)
    }
    wg.Wait()
}
  1. 通道示例
package main

import (
    "fmt"
    "sync"
)

func dataGenerator(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
}

func dataConsumer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for num := range ch {
        fmt.Printf("Consumer received: %d\n", num)
    }
}

func main() {
    var wg sync.WaitGroup
    ch := make(chan int)
    wg.Add(1)
    go dataGenerator(ch, &wg)
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go dataConsumer(ch, &wg)
    }
    wg.Wait()
}
  1. 原子操作示例
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

var count int64

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    atomic.AddInt64(&count, 1)
    fmt.Printf("Incremented count to %d\n", atomic.LoadInt64(&count))
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
}