是否存在适用于批量资源申请场景的知名算法(类信号量)?
解决方案:计数信号量(Counting Semaphore)
你提到的场景完全可以用计数信号量解决,它原生就支持批量申请/归还N个资源,并非只能单次增减1。
核心原理
计数信号量维护一个内部计数器,对应你的available变量:
- 申请N个资源时,调用
Wait(N)(或类似方法):若当前计数器≥N,则直接减去N并返回;否则阻塞等待,直到其他线程归还资源使计数器≥N。 - 归还N个资源时,调用
Release(N)(或类似方法):计数器增加N,同时唤醒等待队列中满足条件的线程。
各语言实现
C#
C# 提供SemaphoreSlim类(轻量级,适合多核场景)和传统Semaphore类,两者都支持批量操作:
SemaphoreSlim.Wait(int count):批量申请count个资源SemaphoreSlim.Release(int count):批量归还count个资源
示例代码:
// 初始化可用资源数为10 var semaphore = new SemaphoreSlim(10); // 申请3个资源 await semaphore.WaitAsync(3); try { // 使用资源的逻辑 } finally { // 归还3个资源 semaphore.Release(3); }
Go
Go 标准库的sync包没有直接提供支持批量操作的信号量,但可以基于sync.Cond和互斥锁自己实现:
基于标准库的简易实现:
import "sync" type BatchSemaphore struct { mu sync.Mutex cond *sync.Cond available int } func NewBatchSemaphore(initial int) *BatchSemaphore { bs := &BatchSemaphore{available: initial} bs.cond = sync.NewCond(&bs.mu) return bs } // Acquire 申请n个资源,阻塞直到可用 func (bs *BatchSemaphore) Acquire(n int) { bs.mu.Lock() defer bs.mu.Unlock() for bs.available < n { bs.cond.Wait() } bs.available -= n } // Release 归还n个资源,唤醒等待的goroutine func (bs *BatchSemaphore) Release(n int) { bs.mu.Lock() defer bs.mu.Unlock() bs.available += n bs.cond.Broadcast() }
使用示例:
sem := NewBatchSemaphore(10) // 申请4个资源 sem.Acquire(4) defer sem.Release(4) // 资源使用逻辑
补充说明
- 计数信号量完全匹配你的场景:资源归还触发唤醒,而非基于时间间隔;支持任意整数N的批量操作。
- 手动实现时注意用
Broadcast唤醒等待队列,避免线程饥饿问题;优先使用语言原生提供的类(如C#的SemaphoreSlim)更稳妥。
内容的提问来源于stack exchange,提问作者Marlon
相关产品推荐
相关产品推荐

