跳到主要内容

ValkarnSemaphore

ValkarnSemaphore 是一个基于 ValkarnTask 构建的零分配异步信号量。它的工作方式类似于 SemaphoreSlim,但与 Valkarn Tasks 管道原生集成——在稳定状态下无 Task 分配,无 GC 压力。

namespace UnaPartidaMas.Valkarn.Tasks

快速路径(无竞争): 立即返回 ValkarnTask.CompletedTask——零分配。 慢速路径(有竞争): 等待节点从有界池中租借,完成后归还——稳定状态下 GC 为零。


构造函数

public ValkarnSemaphore(int initialCount, int maxCount)
参数描述
initialCount立即可用的槽位数量。必须在 [0, maxCount] 范围内。
maxCount槽位数量的上限。必须 > 0。

属性

public int CurrentCount { get; } // 当前可用槽位数(线程安全)

方法

WaitAsync

public ValkarnTask WaitAsync(CancellationToken ct = default)

异步获取一个槽位。如果有可用槽位,立即返回已完成的 ValkarnTask(零分配)。若没有可用槽位,则挂起调用方直到 Release() 被调用。等待者按 FIFO 顺序服务。

如果 ct 在等待期间触发,则抛出 OperationCanceledException

Wait

public void Wait(CancellationToken ct = default)

同步变体。如果没有可用槽位,则阻塞调用线程。仅在无法使用 await 时使用(例如非异步入口点)。

Release

public void Release(int releaseCount = 1)

归还 releaseCount 个槽位。待处理的等待者按 FIFO 顺序完成,在内部锁之外执行——续延永远不会在持有锁的情况下运行。

如果释放后超过 maxCount,则抛出 InvalidOperationException

Dispose

public void Dispose()

取消所有待处理的等待者并释放资源。幂等操作。


用法

互斥(1 个槽位)

var sem = new ValkarnSemaphore(initialCount: 1, maxCount: 1);

async ValkarnTask WriteFileAsync(string path, string content, CancellationToken ct)
{
await sem.WaitAsync(ct);
try
{
await File.WriteAllTextAsync(path, content, ct);
}
finally
{
sem.Release();
}
}

有界并发(N 个槽位)

// 允许最多 4 个并发网络请求。
var sem = new ValkarnSemaphore(initialCount: 4, maxCount: 4);

async ValkarnTask FetchAsync(string url, CancellationToken ct)
{
await sem.WaitAsync(ct);
try
{
await DownloadAsync(url, ct);
}
finally
{
sem.Release();
}
}

生产者 / 消费者门控

// 从 0 个槽位开始——消费者等待直到生产者发出信号。
var gate = new ValkarnSemaphore(initialCount: 0, maxCount: 1);

async ValkarnTask ProducerAsync(CancellationToken ct)
{
await ProduceDataAsync(ct);
gate.Release(); // 通知消费者
}

async ValkarnTask ConsumerAsync(CancellationToken ct)
{
await gate.WaitAsync(ct); // 等待信号
await ConsumeDataAsync(ct);
}

线程安全

所有操作均为线程安全。Release() 可从任意线程调用,包括后台线程。完成操作在内部锁之外分发——重新进入信号量的续延不会发生死锁。


与 SemaphoreSlim 的比较

ValkarnSemaphoreSemaphoreSlim
快速路径分配
慢速路径分配池化节点,GC 为零Task 分配
与 ValkarnTask 集成需要 .AsValkarnTask()
IDisposable
FIFO 排序
取消支持