在 Go语言并发编程 中,控制并发访问共享资源是一个常见且关键的问题。虽然 Go 提供了 goroutine 和 channel 这样的原生并发工具,但有时我们仍需要类似传统“信号量”(Semaphore)的机制来限制同时访问某个资源的 goroutine 数量。本文将手把手教你如何使用 Go 的 通道(channel) 来实现一个轻量级、高效的信号量,帮助你掌握 Go并发控制 的核心技巧。
信号量是一种用于控制多个线程或协程对共享资源进行访问的同步机制。它维护一个计数器,表示当前可用的“许可”数量。当一个协程想要访问资源时,必须先获取一个许可(计数减1);使用完后释放许可(计数加1)。如果许可为0,则后续请求将被阻塞,直到有许可被释放。
Go 语言没有内置的信号量类型,但它的 通道(channel)同步 特性天然适合实现信号量:
下面我们定义一个简单的信号量结构体,并封装获取(Acquire)和释放(Release)方法。
package mainimport ( "fmt" "sync" "time")// Semaphore 使用 channel 实现的信号量type Semaphore struct { ch chan struct{}}// NewSemaphore 创建一个新的信号量,maxConcurrent 表示最大并发数func NewSemaphore(maxConcurrent int) *Semaphore { return &Semaphore{ ch: make(chan struct{}, maxConcurrent), }}// Acquire 获取一个许可(可能会阻塞)func (s *Semaphore) Acquire() { s.ch <- struct{}{}}// Release 释放一个许可func (s *Semaphore) Release() { <-s.ch}
假设我们要同时下载多个文件,但最多只允许 3 个并发下载任务。我们可以使用上面实现的信号量来控制:
func downloadFile(id int, sem *Semaphore, wg *sync.WaitGroup) { defer wg.Done() // 获取许可 sem.Acquire() defer sem.Release() // 确保释放 fmt.Printf("开始下载文件 %d\n", id) time.Sleep(2 * time.Second) // 模拟耗时操作 fmt.Printf("完成下载文件 %d\n", id)}func main() { sem := NewSemaphore(3) // 最多3个并发 var wg sync.WaitGroup // 启动10个下载任务 for i := 1; i <= 10; i++ { wg.Add(1) go downloadFile(i, sem, &wg) } wg.Wait() fmt.Println("所有下载任务完成!")}
运行这段代码,你会发现任何时候最多只有 3 个 “开始下载” 的日志同时出现,这正是我们通过 信号量实现 达到的效果。
通过本教程,你已经学会了如何利用 Go 语言的 通道(channel)同步 机制,轻松实现一个功能完整的信号量。这种模式在限制数据库连接池、控制 API 调用频率、管理 worker pool 等场景中非常实用。掌握这一技巧,将大大提升你在 Go语言并发编程 中的控制力和代码健壮性。
关键词回顾:Go语言并发编程、信号量实现、通道(channel)同步、Go并发控制。
本文由主机测评网于2025-12-05发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025123109.html