.NET 中 Channel 类简单使用

Channel 是干什么的

The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consumers asynchronously. The library targets .NET Standard and works on all .NET implementations.
Channels are an implementation of the producer/consumer conceptual programming model.
以上是微软官方的解释 channels。用中文说的话就是这个类提供了在生产者跟消费者之间异步传统数据的能力,简单来说可以认为是一个内存消息队列。

示例 1

下面是一个简单的示例,说明如何使用 Channel 类来创建一个生产者-消费者模型:

    static async Task Main(string[] args){var channel = Channel.CreateUnbounded<int>();var producer = Task.Run(async () =>{for (int i = 0; i < 10; i++){await channel.Writer.WriteAsync(i);await Task.Delay(1000); // 模拟生产者需要一些时间来生成数据}channel.Writer.Complete();});var consumer = Task.Run(async () =>{await foreach (var item in channel.Reader.ReadAllAsync()){Console.WriteLine($"消费者接收到: {item}");}});await Task.WhenAll(producer, consumer);}

在这个例子中,我们创建了一个无界的通道,然后创建了两个任务,一个是生产者,一个是消费者。生产者每秒生成一个数字,然后写入通道。消费者从通道中读取数据并打印出来。当生产者完成写入后,它会调用 channel.Writer.Complete() 来通知消费者没有更多的数据可以读取。

示例 2

你可以使用 Channel.CreateBounded(capacity) 方法来创建一个有界的通道,其中 capacity 参数指定了通道的容量。当通道满时,尝试写入的操作将会阻塞,直到有空间可用。

    static async Task Main(string[] args){var channel = Channel.CreateBounded<int>(5); // 创建一个容量为5的有界通道var producer = Task.Run(async () =>{for (int i = 0; i < 10; i++){await channel.Writer.WriteAsync(i);Console.WriteLine($"生产者生成了: {i}");await Task.Delay(1000); // 模拟生产者需要一些时间来生成数据}channel.Writer.Complete();});var consumer = Task.Run(async () =>{await foreach (var item in channel.Reader.ReadAllAsync()){Console.WriteLine($"消费者接收到: {item}");await Task.Delay(2000); // 模拟消费者需要一些时间来处理数据}});await Task.WhenAll(producer, consumer);}

在这个例子中,我们创建了一个容量为5的有界通道。生产者每秒生成一个数字,然后写入通道。消费者从通道中读取数据并打印出来,但消费者处理数据的速度比生产者慢,所以当通道满时,生产者的 WriteAsync 操作将会阻塞,直到消费者读取了一些数据,使得通道有空间可用。

示例 3

下面是一个示例,展示了如何在多个生产者和消费者之间共享一个通道:

    static async Task Main(string[] args){var channel = Channel.CreateUnbounded<int>();// 创建两个生产者var producer1 = Produce(channel.Writer, id: 1);var producer2 = Produce(channel.Writer, id: 2);// 创建两个消费者var consumer1 = Consume(channel.Reader, id: 1);var consumer2 = Consume(channel.Reader, id: 2);// 等待所有生产者和消费者完成await Task.WhenAll(producer1, producer2, consumer1, consumer2);}static async Task Produce(ChannelWriter<int> writer, int id){for (int i = 0; i < 10; i++){await writer.WriteAsync(i);Console.WriteLine($"生产者{id}生成了: {i}");await Task.Delay(1000); // 模拟生产者需要一些时间来生成数据}writer.Complete();}static async Task Consume(ChannelReader<int> reader, int id){await foreach (var item in reader.ReadAllAsync()){Console.WriteLine($"消费者{id}接收到: {item}");await Task.Delay(2000); // 模拟消费者需要一些时间来处理数据}}

在这个例子中,我们创建了两个生产者和两个消费者,它们都共享同一个通道。这是一个非常重要使用模式。因为当我们使用消息队列的时候往往会有多个生产者跟多个消费者。我们可以通过控制生产者生产的速度来控制推入队列的数据量。我们还可以通过控制消费者的数量来控制消费数据的速度,从而来调节系统的流量,达到消峰填谷的作用。

总结

Channel 类是 .NET CORE 3.0 后新加入的类。为我们提供了便利的生产者/消费者模式实现方案。相当于是一个进程内的内存队列,而且它没有持久化,纯内存操作,性能是非常非常高的。当我们面对真正的高并发的时候可以为我们的系统提供吞吐量。当然代价是内存跟放弃一些实时性。

关注我的公众号一起玩转技术

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/709011.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第五周-云计算运维作业

1. 总结openssh服务安全加固和总结openssh免密认证原理,及免认证实现过程。 1.仅使用SSHv2 协议 2.关闭或者延迟压缩 Compression no 3.限制身份验证最大尝试次数 MaxAuthTries 3 4.禁用root账户登录 PermitRootLogin no 5.显示最后一次登录的日期和时间 PrintLastLog yes #用…

深入掌握service

深入掌握Service Service是Kubernetes实现微服务架构的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。 Service定义 Service用于为一组提供服务的Pod抽象一个稳定的网络访问地址,是Kuberne…

uniapp-webview获取h5页面加载错误信息及自定义错误页面(捕获uniapp中webview加载error)

问题描述uniapp中需要加载H5页面,使用了webview,但是在某些情况下,页面加载出现错误,但是官方文档里给出的捕获错误信息的回调函数,只适用部分平台,某些平台无法获取@error异常信息,这种情况如何处理呢? 解决uniapp web-view组件的@load @error事件无效,事件不触发的问…

物联网在智慧园区的八大应用

物联网在智慧园区领域有许多应用。以下是一些常见的应用场景: 智能安防系统: 通过物联网技术,可以实现智能监控、入侵检测、视频监控、智能门禁等安防功能,提高园区的安全性和管理效率。 能源管理: 物联网可以用于实时监测和控制园区内的能源消耗,包括电力、水、气等,通…

tensorflow与python版本对应关系

下完之后才发现tensorflow1.12.0需要3.6的版本……

听说你是高手?说说你的 JVM调优方法论 吧?(美团面试,问的贼细)

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

一个页面从输入URL到加载显示完成,这个过程发生了什么?

目录一、解析URL1、流程2、URL格式:3、示例二、浏览器封装HTTP请求报文1、流程2、HTTP请求报文例子3、封装三、DNS解析1、缓存判断1.1、浏览器缓存1.2、操作系统缓存1.3、路由器缓存2、递归查询至ISP DNS服务器3、迭代查询过程4、保存结果至各级缓存四、建立TCP连接(三次握手…

vscode 无法调试 golang testify suite 中的单个 test 的解决办法

目录问题描述网上的讨论最终的解决办法 问题描述 对于如下这样简单的测试文件: package main// Basic imports import ("testing""github.com/stretchr/testify/assert""github.com/stretchr/testify/suite" )var assertObj *assert.Assertions/…

【Linux】Deepin安装Anaconda后手动配置环境变量

配置环境变量 如果安装完毕后,重新打开终端,输入conda表示没找到这个命令 说明没有配置环境变量 那么我们首先第一件事,就是找到我们的conda安装到哪里了例如我的是安装到主目录的(默认在这的,安装的时候我没有修改安装路径) 然后进入这个文件夹,进入bin,在bin下运行终端…

Redis 缓存常见问题处理

缓存穿透 缓存穿透是指客户端的请求数据在缓存和数据库中都不存在,这样缓存永远不会生效,这些请求都会到达数据库,从而导致数据库负载过高。 常见解决方案有两种:缓存空对象:实现简单、方便维护,是解决缓存穿透的首选方法,但会造成额外内存消耗,或短期的数据不一致 布隆…

[原]代码管理工具WeCode及其数据导出

1.WeCode简介SVN、Git等工具适合多人协作时代码管理。类似在线的Gist(http://gist.github.com),WeCode是适合个人离线代码片段管理。wecode是CodeHelp的升级版本,是专门为我们程序员设计的一款源代码管理软件。 它能方便的管理您在编程和学习中有用的源代码,减少经常到处查找…