You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否存在适用于批量资源申请场景的知名算法(类信号量)?

解决方案:计数信号量(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 02:45:10