17人参与 • 2025-12-01 • Asp.net
在 c#(.net)中,semaphore 和 semaphoreslim 都用于控制同时访问某一资源或池的线程数量(即“信号量”机制),但它们在实现方式、性能、功能和适用场景上有显著区别。
下面从多个维度详细对比两者,并附使用示例。
| 特性 | semaphore | semaphoreslim |
|---|---|---|
| 命名空间 | system.threading | system.threading |
| 底层实现 | 内核模式(windows 内核信号量对象) | 用户模式 + 混合模式(优先自旋,必要时用内核事件) |
| 跨进程支持 | ✅ 支持(可通过名称创建命名信号量) | ❌ 不支持 |
| 异步支持 | ❌ 无 waitasync() | ✅ 支持 waitasync() |
| 性能 | 较低(每次 wait/release 涉及内核切换) | 较高(短竞争无内核开销) |
| 适用场景 | 跨进程同步、长时间等待 | 进程内同步、高性能、异步编程 |
| 是否可重入 | 否 | 否 |
| 释放行为 | 必须由获取线程释放(但无所有权概念) | 同左 |
semaphore:
// 进程 a
var sem = new semaphore(2, 2, "myglobalsemaphore");
// 进程 b
var sem = semaphore.openexisting("myglobalsemaphore");
适用于多个进程共享有限资源(如硬件设备、全局连接池)。
semaphoreslim:
manualreseteventslim 或自旋,无内核对象名称。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(); // 阻塞当前线程!
semaphoreslim:
spinwait),失败后才使用轻量内核事件。semaphore:
waitone() / release() 都触发内核模式切换(约 1000~3000 纳秒开销)。📊 性能测试表明:在高频短临界区场景,semaphoreslim 比 semaphore 快 5~10 倍以上。
| 功能 | semaphore | semaphoreslim |
|---|---|---|
| 构造函数 | semaphore(initialcount, maximumcount, name?) | semaphoreslim(initialcount, maxcount?) |
| 等待 | waitone(), waitone(timeout) | wait(), wait(timeout), waitasync(), waitasync(timeout) |
| 释放 | release(), release(count) | release(), release(count) |
| 打开现有(跨进程) | openexisting(name) | ❌ 不支持 |
// 使用 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 等高并发环境。
进程 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(命名) |
lock)保护共享数据。// ❌ 错误:在 waitasync 后又同步阻塞 await _sem.waitasync(); thread.sleep(1000); // 浪费线程!应使用 await task.delay(1000)
semaphorefullexception。try/finally 包裹。| 对比项 | semaphore | semaphoreslim |
|---|---|---|
| 定位 | 通用、跨进程 | 高性能、进程内 |
| 灵魂特性 | 跨进程 | 异步支持(waitasync) |
| 现代 .net 首选 | 仅当需要跨进程时 | ✅ 绝大多数场景 |
🎯 默认选择 semaphoreslim;只有需要跨进程时才用 semaphore。
到此这篇关于c# semaphore与semaphoreslim区别小结的文章就介绍到这了,更多相关c# semaphore semaphoreslim内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论