C#如何使用Channel C#通道实现异步通信
技术百科
星降
发布时间:2026-01-02
浏览: 次 Channel 是 .NET 轻量、线程安全的异步生产者-消费者通信原语,支持无界/有界模式,提供 WriteAsync/ReadAllAsync 等简洁 API,适用于后台任务、管道处理等场景,需调用 Complete() 通知结束,有界容量需权衡吞吐与延迟。
c#通道实现异步通信">
Channel
创建和配置 Channel
Channel 有无界(Unbounded)和有界(Bounded)两种类型,选择取决于你对内存控制和背压(backpressure)的需求:
-
无界 Channel:缓冲区无限增长,适合吞吐优先、不担心内存溢出的场景(如日志采集)
var channel = Channel.CreateUnbounded(); -
有界 Channel:指定容量,写入时若满则默认等待(可设为丢弃或抛异常),适合需要流量控制的场景(如实时消息队列)
var channel = Channel.CreateBounded(capacity: 100);
写入数据(Producer)
使用 Writer 写入,支持同步和异步方式。推荐用 WriteAsync 配合 await,尤其对有界 Channel 能自然等待空闲空间:
- 写入单个值:await channel.Writer.WriteAsync("hello");
- 批量写入(高效):await channel.Writer.WriteAsync(new[] {"a", "b", "c"});
- 标记写入完成(通知消费者停止读取):channel.Writer.Complete();
读取数据(Consumer)
使用 Reader 读取,核心是 ReadAsync —— 它会挂起直到有数据或 Channel 关闭:
- 基础读取循环:
while (await channel.Reader.WaitToReadAsync())
while (channel.Reader.TryRead(out var item))
Console.WriteLine(item); - 更简洁写法(推荐):
await foreach (var item in channel.Reader.ReadAllAsync())
Console.WriteLine(item); - 注意:ReadAllAsync 会在 Writer.Complete() 后自动退出循环,无需手动判断。
组合多个 Channel 实现管道
Channel 天然适合构建链式处理管道。例如:接收原始日志 → 过滤 → 格式化 → 输出:
- 启动一个后台任务做过滤:
_ = Task.Run(async () => {
await foreach (var line in input.Reader.ReadAllAsync())
if (line.Contains("ERROR"))
await filtered.Writer.WriteAsync(line);
filtered.Writer.Complete();
}); - 后续环节消费
filteredChannel,彼此完全解耦,且自动异步流控。
基本上就这些。Channel 不复杂但容易忽略两点:一是别忘了调用 Complete() 告诉消费者“没新数据了”,二是有界 Channel 的容量设置要结合实际吞吐和延迟容忍度来权衡。
# ai
# 会在
# 是有
# 多个
# 它会
# 链式
# 适用于
# 一是
# 设为
# input
# 循环
# Error
# 并发
# String
# if
# int
# c#
# .net
# console
# 线程
# 异步
# 事件
# red
# var
# foreach
# while
# 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; ?>
】
相关推荐
- 如何使用Golang处理静态文件缓存_提高页面加载
- 如何在 Go 中判断变量是否为函数类型
- Win11怎么修复系统文件_使用sfc命令修复Wi
- 如何使用正则表达式提取以编号开头、后跟多个注解的完
- Windows10如何更改任务栏高度_Win10解
- c++中如何进行二进制文件读写_c++ read与
- Win11怎么设置多显示器任务栏 Win11扩展任
- 如何在 Go 同包不同文件中正确引用结构体
- php会话怎么开启_session_start函数
- Win11怎样激活系统密钥_Win11系统密钥激活
- Win10怎么卸载剪映_Win10彻底卸载剪映方法
- 如何使用Golang构建基础消息队列模拟_Gola
- Win10如何备份驱动程序_Win10驱动备份步骤
- 如何使用Golang构建简易投票统计功能_Gola
- Win11怎么更改输入法顺序_Win11调整语言首
- Win11怎么设置麦克风权限_允许应用访问Win1
- Win11怎么检查TPM2.0模块_Windows
- 如何解决同一段404代码在不同主机上表现不一致的问
- Python生成器表达式内存优化_惰性计算说明【指
- Windows10如何更改计算机工作组_Win10
- 手机php文件怎么变成mp4_安卓苹果打开php转
- MAC怎么解压RAR格式文件_MAC第三方解压工具
- 如何在 Python 中将 ISO 8601 时间
- Win11怎么关闭触控板_Win11笔记本禁用触摸
- Windows10怎样连接蓝牙设备_Windows
- 如何使用Golang log记录不同级别日志_Go
- php查询数据怎么导出csv_查询结果转csv文件
- Win11局域网共享怎么设置 Win11文件夹网络
- Win10如何优化内存使用_Win10内存优化技巧
- mac怎么安装字体_MAC添加第三方字体与字体册管
- MAC怎么截图并快速编辑_MAC自带截图快捷键与标
- Mac如何开启夜览模式_Mac护眼模式设置与定时
- 如何使用Golang encoding/json解
- LINUX如何查看文件类型_Linux中file命
- 如何在Golang中实现邮件发送功能_Golang
- Win10如何更改用户账户控制_Windows10
- Win11怎么忘记WiFi网络_Win11删除已保
- Python文件管理规范_工程实践说明【指导】
- ACF 教程:如何正确更新嵌套在多层 Group
- Win11怎么开启HDR模式_Windows 11
- Windows驱动无法加载错误解决方法_驱动签名验
- C#如何在一个XML文件中查找并替换文本内容
- mac怎么分屏_MAC双屏显示与分屏操作技巧【指南
- Win11时间不对怎么同步_Win11自动校准互联
- PHP主流架构怎么监控运行状态_工具推荐【操作】
- Win11怎么设置任务栏图标大小_Windows1
- 如何在Golang中处理模块包路径变化_Golan
- Win11任务栏怎么放到顶部_Win11修改任务栏
- Win11怎么更改管理员名字 Win11修改账户名
- Win10如何卸载自带Edge_Win10彻底卸载

c/ReadAllAsync 等简洁 API,适用于后台任务、管道处理等场景,需调用 Complete() 通知结束,有界容量需权衡吞吐与延迟。
QQ客服