C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# Semaphore SemaphoreSlim

C# Semaphore与SemaphoreSlim区别小结

作者:她说彩礼65万

本文主要介绍了C# Semaphore与SemaphoreSlim区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在 C#(.NET)中,SemaphoreSemaphoreSlim 都用于控制同时访问某一资源或池的线程数量(即“信号量”机制),但它们在实现方式、性能、功能和适用场景上有显著区别。

下面从多个维度详细对比两者,并附使用示例。

一、核心区别概览

特性SemaphoreSemaphoreSlim
命名空间System.ThreadingSystem.Threading
底层实现内核模式(Windows 内核信号量对象)用户模式 + 混合模式(优先自旋,必要时用内核事件)
跨进程支持✅ 支持(可通过名称创建命名信号量)❌ 不支持
异步支持❌ 无 WaitAsync()✅ 支持 WaitAsync()
性能较低(每次 Wait/Release 涉及内核切换)较高(短竞争无内核开销)
适用场景跨进程同步、长时间等待进程内同步、高性能、异步编程
是否可重入
释放行为必须由获取线程释放(但无所有权概念)同左

二、详细对比说明

1.跨进程支持

Semaphore

// 进程 A
var sem = new Semaphore(2, 2, "MyGlobalSemaphore");

// 进程 B
var sem = Semaphore.OpenExisting("MyGlobalSemaphore");

适用于多个进程共享有限资源(如硬件设备、全局连接池)。

SemaphoreSlim

2.异步支持(关键区别!)

SemaphoreSlim 提供 WaitAsync() 方法,完美支持 async/await

private static SemaphoreSlim _sem = new SemaphoreSlim(3);

public async Task ProcessAsync()
{
    await _sem.WaitAsync(); // 异步等待,不阻塞线程
    try
    {
        await CallExternalApiAsync(); // 模拟 I/O 操作
    }
    finally
    {
        _sem.Release();
    }
}

✅ 非常适合 Web API、高并发 I/O 场景(如限流)。

Semaphore 只有同步方法 WaitOne(),在异步上下文中会阻塞线程,导致线程池饥饿:

// ❌ 不推荐在 async 方法中使用
sem.WaitOne(); // 阻塞当前线程!

3.性能差异

📊 性能测试表明:在高频短临界区场景,SemaphoreSlim 比 Semaphore 快 5~10 倍以上。

4.API 差异

功能SemaphoreSemaphoreSlim
构造函数Semaphore(initialCount, maximumCount, name?)SemaphoreSlim(initialCount, maxCount?)
等待WaitOne(), WaitOne(timeout)Wait(), Wait(timeout), WaitAsync(), WaitAsync(timeout)
释放Release(), Release(count)Release(), Release(count)
打开现有(跨进程)OpenExisting(name)❌ 不支持

三、使用示例对比

✅ 场景:限制并发 HTTP 请求(推荐用SemaphoreSlim)

// 使用 SemaphoreSlim(支持异步)
private static readonly SemaphoreSlim _throttle = new SemaphoreSlim(5, 5);

public async Task<string> FetchDataAsync(string url)
{
    await _throttle.WaitAsync(); // 异步等待,不占线程
    try
    {
        using var client = new HttpClient();
        return await client.GetStringAsync(url);
    }
    finally
    {
        _throttle.Release();
    }
}

✅ 高效、不阻塞线程池线程,适合 ASP.NET Core 等高并发环境。

✅ 场景:两个进程共享最多 2 个数据库连接(必须用Semaphore)

进程 A:

var sem = new Semaphore(2, 2, "Global\\DBConnectionPool");
sem.WaitOne();
// 使用数据库连接...
sem.Release();

进程 B:

var sem = Semaphore.OpenExisting("Global\\DBConnectionPool");
sem.WaitOne();
// 使用数据库连接...
sem.Release();

✅ 只有 Semaphore 能跨进程协调资源。

四、如何选择?

需求推荐类型
进程内同步 + 异步支持✅ SemaphoreSlim
高性能、低延迟✅ SemaphoreSlim
跨进程同步✅ Semaphore
长时间持有信号量⚠️ 两者皆可,但 Semaphore 更稳定
Web 服务限流、API 调用控制✅ SemaphoreSlim(配合 WaitAsync)
桌面应用多实例共享资源✅ Semaphore(命名)

五、注意事项

1.SemaphoreSlim不是线程安全的“计数器”

2.避免在SemaphoreSlim中阻塞线程

// ❌ 错误:在 WaitAsync 后又同步阻塞
await _sem.WaitAsync();
Thread.Sleep(1000); // 浪费线程!应使用 await Task.Delay(1000)

3.Release()调用次数不能超过Wait()

✅ 总结

对比项SemaphoreSemaphoreSlim
定位通用、跨进程高性能、进程内
灵魂特性跨进程异步支持(WaitAsync)
现代 .NET 首选仅当需要跨进程时✅ 绝大多数场景

🎯 默认选择 SemaphoreSlim;只有需要跨进程时才用 Semaphore。

到此这篇关于C# Semaphore与SemaphoreSlim区别小结的文章就介绍到这了,更多相关C# Semaphore SemaphoreSlim内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文