C# 如何使用Channel - .NET中高性能的生产者消费者队列
技术百科
幻夢星雲
发布时间:2025-12-06
浏览: 次 Channel 是 .NET 5+ 推荐的异步生产者-消费者通信原语,相比 Queue 和 BlockingCollection 更轻量、支持无锁操作、内置完成与取消感知,具备有界/无界模式以控制背压,Reader/Writer 可分离实现组件解耦,配合 TryRead 批处理与 WriteAsync 等待机制,适用于高并发低延迟场景如实时消息处理与任务管道。
- .net中高性能的生产者消费者队列">
ChannelBlockingCollection 更轻量、更灵活,尤其适合高并发、低
延迟场景(如实时消息处理、后台任务管道、流式数据处理)。
为什么选 Channel 而不是 Queue 或 BlockingCollection?
它不是线程安全的普通队列,而是一个**异步就绪的通道(channel)**,天然支持:
- 无锁、零分配(在多数配置下)的写入/读取
- 内置完成(
Writer.Complete())和取消感知(可传CancellationToken) - 支持“有界”(Bounded)与“无界”(Unbounded)两种模式,可控内存增长
- Reader 和 Writer 可分离传递,便于解耦组件(比如一个服务只写,另一个只读)
快速上手:创建与基本用法
最简示例(无界 Channel):
var channel = Channel.CreateUnbounded(); var reader = channel.Reader; var writer = channel.Writer; // 生产者(异步写入) _ = Task.Run(async () => { await writer.WriteAsync("Hello"); await writer.WriteAsync("World"); writer.Complete(); // 标记不再写入 }); // 消费者(异步读取) await foreach (var msg in reader.ReadAllAsync()) { Console.WriteLine(msg); // 输出 Hello,然后 World }
注意:ReadAllAsync() 会自动等待新项、响应完成信号,并在通道关闭后退出循环。
控制背压:使用有界 Channel 防止内存爆炸
当生产快于消费时,无界 Channel 会导致内存无限堆积。改用有界 Channel 可自然施加背压:
// 最多缓存 100 个字符串,超出时 WriteAsync 会 await(阻塞生产者直到有空位) var channel = Channel.CreateBounded(new BoundedChannelOptions(100) { FullMode = BoundedChannelFullMode.Wait // 默认行为;也可设为 DropWrite / DropOldest });
常见策略:
-
FullMode = Wait:默认,生产者等待空位(最常用,保证不丢数据) -
FullMode = DropWrite:新数据直接丢弃(适合监控指标等非关键流) -
FullMode = DropOldest:挤掉最老的数据腾位置(适合滑动窗口场景)
进阶技巧:手动读取 + 异常处理 + 取消支持
不用 await foreach 时,可用 TryRead(非阻塞)或 ReadAsync(异步阻塞),并配合取消令牌:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
while (await reader.WaitToReadAsync(cts.Token))
{
while (reader.TryRead(out var item))
{
Process(item);
}
}
}
catch (OperationCanceledException)
{
Console.WriteLine("读取被取消");
}
catch (ChannelClosedException)
{
Console.WriteLine("通道已关闭");
}
关键点:
-
WaitToReadAsync()等待有新数据或关闭,避免忙等 -
TryRead()批量消费当前所有可用项(推荐,减少 await 开销) - 始终检查
ChannelReader.Completion.IsFaulted判断是否因异常关闭
基本上就这些。ChannelTryRead 批处理、别忘了 Complete() 和取消传播。它不是万能队列,而是为异步流水线设计的“管道”,用对了,吞吐翻倍,延迟归零。
# ai
# 最多
# 进阶
# 并在
# 适用于
# 令牌
# 两种
# 设为
# 循环
# 并发
# 堆
# c#
# .net
# 为什么
# 线程
# 异步
# 无锁
# foreach
# channel
# 无界
# 批处理
# 可分离
相关栏目:
<?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; ?>
】
相关推荐
- VSC怎么在PHP中调试MySQL_数据库交互排查
- 如何使用Golang开发简单的聊天室消息存储_Go
- php下载安装包怎么选_threadsafe与nt
- Win11怎么关闭定位服务_保护Win11位置隐私
- Windows系统被恶意软件破坏后的恢复策略_错误
- 如何在 IIS 上为 ASP.NET 6 应用排除
- php怎么操作Redis_Redis扩展连接与基本
- Win11怎么关闭应用权限_Windows11相机
- 如何在 Go 中比较自定义的数组类型(如 [20]
- 网站内页做seo排名怎么做?
- 如何在Golang中处理通道发送接收错误_防止阻塞
- Win11怎么开启移动热点_Windows11共享
- Linux怎么设置磁盘配额_Linux系统Quot
- Win10怎样设置闹钟贪睡时间 Win10闹钟贪睡
- Win11如何更新显卡驱动 Win11检查和安装设
- 如何使用Golang管理跨项目依赖_Golang多
- Win11摄像头无法使用怎么办_Win11相机隐私
- Win11如何设置电源计划_Win11电源计划优化
- php怎么下载安装后无法解析php文件_服务器配置
- 如何在Golang中实现微服务负载均衡_Golan
- php嵌入式多设备通信怎么实现_php同时管理多个
- c++20的std::format怎么用 比pri
- 如何从 Go 的 map[string]inter
- php8.4如何调用com组件_php8.4win
- Linux怎么禁止Root用户远程登录_Linux
- Win11怎么关闭粘滞键_彻底禁用Windows
- Win11无法安装软件怎么办_Win11解除应用安
- Mac怎么安装软件_Mac安装dmg与pkg文件的
- php查询数据怎么分组_groupby分组查询配合
- c++中explicit(bool)的用法 c++
- Windows怎样关闭开始菜单推荐广告_Windo
- php打包exe如何加密代码_防反编译保护方法【技
- Win11怎么设置夜间模式_Windows11显示
- Django 密码修改后会话失效的解决方案
- 怎么将XML数据可视化 D3.js加载XML
- Win11怎么查看显卡温度 Win11任务管理器查
- php怎么捕获异常_trycatch结构处理运行时
- Win10如何优化内存使用_Win10内存优化技巧
- Win11怎么关闭防火墙通知_屏蔽Win11安全中
- php内存溢出怎么排查_php内存限制调试与优化方
- 如何使用Golang recover捕获panic
- Windows 11登录时提示“用户配置文件服务登
- php报错怎么查看_定位PHP致命错误与警告的方法
- Windows10如何彻底关闭自动更新_Win10
- 如何在 Laravel 中通过嵌套关联关系进行 o
- Mac如何整理桌面文件_Mac使用堆栈功能一键整理
- Windows10蓝屏SYSTEM_SERVICE
- LINUX怎么查看进程_LINUX ps命令查看运
- Windows系统文件被保护机制阻止怎么办_权限不
- 如何在Golang中使用闭包_封装变量与函数作用域

QQ客服