面试题答案
一键面试- 保证并发安全:
- 在Go语言中,可以使用
sync.Mutex
(互斥锁)来保证对共享资源的安全访问。互斥锁可以确保在同一时间只有一个协程能够访问共享资源。 - 示例代码如下:
- 在Go语言中,可以使用
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
numRoutines := 10
for i := 0; i < numRoutines; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Final counter value:", counter)
}
在上述代码中,mu
是一个sync.Mutex
实例。在对counter
这个共享资源进行累加操作前,先调用mu.Lock()
获取锁,操作完成后调用mu.Unlock()
释放锁,这样就保证了在同一时间只有一个协程可以修改counter
,从而保证了并发安全。
- 性能优化:
- 减少锁的粒度:如果可能,尽量缩小锁保护的代码范围,只对真正需要保护的共享资源操作加锁。例如,如果在对全局变量累加操作前后还有其他不需要保护的操作,可以将这些操作放在锁的外面。
- 使用
sync.RWMutex
(读写互斥锁):如果读操作远多于写操作,可以使用读写互斥锁。读操作时多个协程可以同时进行,只有写操作需要独占锁。 - 示例代码(使用
sync.RWMutex
优化读多写少场景):
package main
import (
"fmt"
"sync"
)
var (
data int
rwmu sync.RWMutex
)
func readData(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.RLock()
fmt.Println("Read data:", data)
rwmu.RUnlock()
}
func writeData(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.Lock()
data++
rwmu.Unlock()
}
func main() {
var wg sync.WaitGroup
numReaders := 5
numWriters := 2
for i := 0; i < numReaders; i++ {
wg.Add(1)
go readData(&wg)
}
for i := 0; i < numWriters; i++ {
wg.Add(1)
go writeData(&wg)
}
wg.Wait()
}
在这个示例中,读操作使用rwmu.RLock()
获取读锁,允许多个协程同时读,写操作使用rwmu.Lock()
获取写锁,保证写操作的原子性,从而在保证并发安全的前提下提升了性能,尤其在读多写少的场景下。