可能的性能瓶颈分析
- 信号量竞争:在高并发场景下,大量的goroutine同时竞争信号量,导致频繁的上下文切换和锁竞争,这会消耗大量的CPU时间。
- 资源分配与释放开销:每次获取和释放信号量都有一定的开销,在高并发时,这种开销可能会累积,影响性能。
- 共享资源访问序列化:信号量的使用将对共享资源的访问序列化,即使某些操作可以并行执行,也会因为信号量的限制而串行化,降低了并发效率。
优化方案
- 增加信号量数量:适当增加信号量的数量,允许更多的goroutine同时访问共享资源,减少竞争。
- 分段锁:将共享资源分成多个部分,每个部分使用独立的信号量控制访问,从而减少竞争范围。
- 读写锁:如果共享资源读多写少,可以使用读写锁,读操作可以并发执行,写操作时独占资源。
优化前后对比代码
- 原始代码(使用单个信号量)
package main
import (
"fmt"
"sync"
"time"
)
var (
semaphore = make(chan struct{}, 1)
sharedResource = 0
)
func worker(wg *sync.WaitGroup) {
semaphore <- struct{}{}
defer func() { <-semaphore; wg.Done() }()
// 模拟对共享资源的操作
sharedResource++
time.Sleep(time.Millisecond)
fmt.Println("Worker updated shared resource:", sharedResource)
}
func main() {
var wg sync.WaitGroup
numWorkers := 100
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
}
- 优化方案1:增加信号量数量
package main
import (
"fmt"
"sync"
"time"
)
var (
semaphore = make(chan struct{}, 10) // 增加信号量数量为10
sharedResource = 0
)
func worker(wg *sync.WaitGroup) {
semaphore <- struct{}{}
defer func() { <-semaphore; wg.Done() }()
// 模拟对共享资源的操作
sharedResource++
time.Sleep(time.Millisecond)
fmt.Println("Worker updated shared resource:", sharedResource)
}
func main() {
var wg sync.WaitGroup
numWorkers := 100
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
}
- 优化方案2:分段锁(以简单数组分段为例)
package main
import (
"fmt"
"sync"
"time"
)
const (
numSegments = 10
)
var (
semaphores = make([]chan struct{}, numSegments)
sharedArray = make([]int, 100)
)
func init() {
for i := 0; i < numSegments; i++ {
semaphores[i] = make(chan struct{}, 1)
}
}
func worker(wg *sync.WaitGroup, index int) {
segmentIndex := index / (len(sharedArray) / numSegments)
semaphores[segmentIndex] <- struct{}{}
defer func() { <-semaphores[segmentIndex]; wg.Done() }()
// 模拟对共享数组的操作
sharedArray[index]++
time.Sleep(time.Millisecond)
fmt.Println("Worker updated shared array at index", index, ":", sharedArray[index])
}
func main() {
var wg sync.WaitGroup
numWorkers := 100
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
}
- 优化方案3:读写锁
package main
import (
"fmt"
"sync"
"time"
)
var (
rwMutex sync.RWMutex
sharedData = 0
)
func reader(wg *sync.WaitGroup) {
rwMutex.RLock()
defer func() { rwMutex.RUnlock(); wg.Done() }()
// 模拟读操作
fmt.Println("Reader read shared data:", sharedData)
time.Sleep(time.Millisecond)
}
func writer(wg *sync.WaitGroup) {
rwMutex.Lock()
defer func() { rwMutex.Unlock(); wg.Done() }()
// 模拟写操作
sharedData++
fmt.Println("Writer updated shared data:", sharedData)
time.Sleep(time.Millisecond)
}
func main() {
var wg sync.WaitGroup
numReaders := 50
numWriters := 50
for i := 0; i < numReaders; i++ {
wg.Add(1)
go reader(&wg)
}
for i := 0; i < numWriters; i++ {
wg.Add(1)
go writer(&wg)
}
wg.Wait()
}