Skip to content
鼓励作者:欢迎打赏犒劳

并发控制

🌰 示例:限制最多 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{} 而不用 boolint

类型内存占用说明
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 包。

如有转载或 CV 的请标注本站原文地址