C#怎么使用SemaphoreSlim C#限制并发线程数量方法
技术百科
月夜之吻
发布时间:2025-12-21
浏览: 次 SemaphoreSlim 是 C# 中专为异步设计的轻量信号量,通过 WaitAsync() 和 Release() 控制并发,需用 try/finally 确保释放,不支持 using,适用于单进程内限流。
SemaphoreSlim 是 C# 中轻量级的信号量实现,专为异步场景设计,适合控制并发访问资源的线程/任务数量。它比传统的 Semaphore 更高效(不依赖操作系统内核),且原生支持 async/await。
初始化并设置最大并发数
构造函数接收两个参数:初始可进入数(通常等于最大并发数)、最大允许数。
- 比如限制最多 3 个任务同时执行:
var semaphore = new SemaphoreSlim(3, 3); - 第一个参数是“当前可用许可数”,第二个是“上限”,两者相等表示初始全空闲
- 若设为
new SemaphoreSlim(0, 3),则初始无人能进入,需手动Release()才能开始
在异步方法中安全获取和释放许可
务必用 await WaitAsync() 获取许可,用 Release() 归还(不能用 await ReleaseAsync(),它不存在)。
- 推荐写法(自动释放,防遗漏):
await semaphore.WaitAsync();
try
{
// 执行受控操作,如调用 API、处理文件等
await DoWorkAsync();
}
finally
{
semaphore.Release(); // 必须确保执行到
}- 别用
using——SemaphoreSlim不实现IDisposable(仅当需要释放底层资源时才调用Dispose(),一般不用) - 避免在
catch块外直接Release(),否则异常时会漏释放,导致许可永久丢失
配合 Task.WhenAll 控制批量任务并发
常见需求:启动 100 个 HTTP 请求,但只允许最多 5 个并发。
- 把所有任务拆成小批次,或用循环 +
WaitAsync控制节奏 - 简洁做法(逐个提交,内部限流):
var tasks = urls.Select(async url =>
{
await semaphore.WaitAsync();
try
{
return await client.GetStringAsync(url);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);- 注意:上面写法本质是“启动 100 个任务,但每个都先抢许可”,实际并发仍可控
- 如果想更明确分批(如每批 5 个),可用
Chunk()+Task.WhenAll嵌套
其他实用细节
-
WaitAsync()可传入CancellationToken,支持取消等待(比如超时或用户中止) -
CurrentCount属性可读取当前剩
余许可数(仅作监控,非原子判断依据) - 不要在同步方法里用
Wait()阻塞等待 —— 容易引发死锁,尤其在 UI 或 ASP.NET 同步上下文中 - 若需跨进程或跨 AppDomain 限流,
SemaphoreSlim不适用,得换Semaphore或分布式方案(如 Redis 信号量)
基本上就这些。SemaphoreSlim 不复杂但容易忽略释放和异常路径,只要守好“try/finally + Release”这个模式,就能稳稳控住并发量。
# ai
# 操作系统
# 就能
# 第一个
# 最多
# 适用于
# 第二个
# 专为
# app
# 设为
# 不支持
# redis
# ui
# http
# 循环
# 并发
# c#
# 构造函数
# .net
# 线程
# 异步
# 死锁
# red
# var
# try
# catch
# finally
# using
# 分布式
# 并发访问
# 信号量
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- c++如何打印函数堆栈信息_c++ backtra
- Win11怎么制作U盘启动盘_Win11原版系统安
- 如何在包含多值的列中精准搜索指定演员?
- php删除数据怎么清空表_truncate与del
- c++ std::atomic如何保证原子性 c+
- PHP主流架构如何做单元测试_工具与流程【详解】
- Windows10系统怎么查看CPU核心数_Win
- Win11怎么设置麦克风权限_允许应用访问Win1
- Win11如何设置文件关联 Win11修改特定文件
- PHP的FastAdmin架构适合二次开发吗_特点
- mac怎么分屏_MAC双屏显示与分屏操作技巧【指南
- windows 10专注助手怎么关闭_window
- 如何用列表一次性对 DataFrame 的指定列应
- Win11怎么设置应用分屏_Windows11贴靠
- 如何使用Golang开发基础文件下载功能_Gola
- 如何在 Go 项目开发中正确处理本地包导入与远程模
- 如何快速验证Golang安装是否成功_运行go v
- Win11笔记本怎么看电池健康度_Win11电池报
- Ajax提交表单PHP怎么接收_处理Ajax发送的
- Mac如何与安卓手机传文件_Mac和Android
- Go 中 := 短变量声明的类型推导机制详解
- mac怎么安装字体_MAC添加第三方字体与字体册管
- MAC怎么截图并快速编辑_MAC自带截图快捷键与标
- LINUX怎么进行文本内容搜索_Linux gre
- Go 中的 := 运算符:类型推导机制与使用边界详
- Python lxml的etree和Element
- Windows 11怎么更改锁屏超时时间_Wind
- Win10怎么关闭自动更新错误重启 Win10策略
- 当网站SEO排名下降时,如何应对?
- Win11怎么设置默认邮件客户端 Win11修改M
- Win11如何设置ipv6 Win11开启IPv6
- Windows11怎么用“记事本”自动换行与编码
- php485支持哪些操作系统_php485跨系统支
- 如何使用Golang table-driven基准
- Python生成器表达式内存优化_惰性计算说明【指
- 静态属性修改会影响所有实例吗_php作用域操作符下
- Windows10如何更改计算机工作组_Win10
- Win11如何设置环境变量 Win11添加和修改系
- VSC怎样在Linux运行PHP_Ubuntu系统
- Win10如何更改任务栏高度_Windows10解
- Win11怎么关闭系统推荐内容_Windows11
- Win11应用商店下载慢怎么办 Win11更改DN
- Linux怎么查找死循环进程_Linux系统负载分
- Win11文件扩展名怎么显示_Win11查看文件后
- XSLT怎么生成动态的HTML属性名和标签名
- 如何使用Golang实现Web表单数据绑定_自动映
- Win11怎样安装剪映专业版_Win11安装剪映教
- php打包exe如何加密代码_防反编译保护方法【技
- 如何在 Python 中将 ISO 8601 时间
- Windows10电脑怎么设置虚拟内存_Win10

余许可数(仅作监控,非原子判断依据)
QQ客服