package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
semaphore := make(chan struct{}, 5)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
semaphore <- struct{}{}
defer func() { <-semaphore }()
fmt.Printf("Request %d is being processed\n", id)
time.Sleep(1 * time.Second)
fmt.Printf("Request %d is finished\n", id)
}(i)
}
wg.Wait()
}
信号量作用原理
- 通道作为信号量:在上述代码中,使用一个带缓冲的通道
semaphore
作为信号量。通道的缓冲区大小为5,这意味着该信号量最多允许5个并发操作。
- 获取信号量:当一个请求到达时,通过
semaphore <- struct{}{}
语句尝试向通道发送一个空结构体。如果通道缓冲区未满,发送操作会立即成功,请求获得信号量,得以继续执行。如果通道缓冲区已满,发送操作会阻塞,直到有其他请求释放信号量(即从通道接收数据),使得缓冲区有空闲位置。
- 释放信号量:在请求处理完成后,通过
<-semaphore
语句从通道接收一个数据,这相当于释放信号量,允许其他阻塞的请求获取信号量并继续执行。通过这种方式,实现了每秒最多处理5个请求的限流功能。