
并发控制
🌰 示例:限制最多 3 个 goroutine 同时工作
在 Go 中,limiter chan struct{} 这样的定义是一种常见的并发控制模式,用于限制同时运行的 goroutine 数量(即“并发限流”或“信号量”机制)。下面我们详细解释它的含义和用途。 ✅ 输出特点:
- 任意时刻最多只有 3 个 worker 在运行。
- 第 4 个 goroutine 会阻塞在
limiter <- struct{}{},直到前面某个 worker 执行<-limiter释放位置。
🔍 1. chan struct{} 是什么?
struct{}是 Go 中的 空结构体,占用 0 字节内存。chan struct{}是一个 只用于传递信号、不传递数据 的通道。- 向
chan struct{}发送或接收一个值(如struct{}{})只是表示“事件发生”,不携带实际数据。
✅ 优点:轻量、高效,适合做“信号通知”或“占位符”。
limiter chan struct{} 的典型用途:控制最大并发数
代码示例
go
package main
import (
"fmt"
"sync"
"time"
)
func main() {
const maxWorkers = 3
limiter := make(chan struct{}, maxWorkers) // 缓冲通道,容量为3
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// 获取“许可”:向 limiter 发送一个空结构体
limiter <- struct{}{}
fmt.Printf("Worker %d started\n", id)
// 模拟工作
time.Sleep(2 * time.Second)
fmt.Printf("Worker %d done\n", id)
// 释放“许可”:从 limiter 接收(或者直接 <-limiter)
<-limiter
}(i)
}
wg.Wait()
fmt.Println("All done!")
}结果
text
Worker 9 started
Worker 0 started
Worker 4 started
Worker 0 done
Worker 5 started
Worker 4 done
Worker 6 started
Worker 9 done
Worker 7 started
Worker 5 done
Worker 8 started
Worker 7 done
Worker 2 started
Worker 6 done
Worker 1 started
Worker 8 done
Worker 3 started
Worker 1 done
Worker 2 done
Worker 3 done
All done!📌 关键原理
limiter是一个带缓冲的通道,缓冲区大小 = 最大并发数。- 发送操作
limiter <- struct{}{}:相当于“申请一个资源槽位”,如果缓冲区满(已达上限),则阻塞等待。 - 接收操作
<-limiter:相当于“释放一个槽位”,让其他 goroutine 可以进入。
这本质上是一个 计数信号量(Counting Semaphore) 的实现。
✅ 为什么用 struct{} 而不用 bool 或 int?
| 类型 | 内存占用 | 说明 |
|---|---|---|
chan bool | 每个元素 1 字节 | 可用,但浪费 |
chan int | 每个元素 8 字节(64位) | 更浪费 |
chan struct{} | 0 字节 | ✅ 最轻量,语义清晰(仅用于同步) |
Go 社区约定俗成用 struct{} 表示“无数据信号”。
✅ 总结
| 代码 | 含义 |
|---|---|
limiter chan struct{} | 一个用于并发控制的信号通道 |
make(chan struct{}, N) | 创建容量为 N 的缓冲通道,代表最多 N 个并发 |
limiter <- struct{}{} | 申请一个并发槽位(若满则阻塞) |
<-limiter | 释放一个槽位 |
这是一种 简洁、高效、地道的 Go 并发控制模式,广泛应用于生产代码中。
如果你需要更高级的限流(如速率限制),可以结合 time.Ticker 或使用 golang.org/x/time/rate 包。

