在C#中使用Channels的完整教程
前言
在面对生产者-消费者的场景下,netcore提供了一个新的命名空间System.Threading.Channels来帮助我们更高效的处理此类问题,有了这个Channels存在,生产者和消费者可以各自处理自己的任务而不相互干扰,有利于两方的并发处理,这篇文章我们就来讨论下如何使用System.Threading.Channels。
DataflowvsChannel
在System.Threading.Tasks.Dataflow命名空间下提供了一个数据流库,主要封装了存储和处理两大块,该库专注于pipeline处理,而System.Threading.Tasks.Channels主要专注于存储这块,从单一职责上来说,在生产者-消费者场景下,Channels比Dataflow性能要高得多。
为什么要使用Channels
可以利用Channels来实现生产者和消费者之间的解耦,大体上有两个好处:
- 生产者和消费者是相互独立的,两者可以并行执行。
- 如果生产者不给力,可以创建多个的生产者,如果消费者不给力,可以创建更多的消费者。
总的来说,在生产者-消费者模式下可以帮助我们提高应用程序的吞吐率。
安装System.Threading.Channels
要想使用Channel,需要用nuget引用System.Threading.Channels包,还可以通过VisualStudio2019的NuGetpackagemanager可视化界面安装或者通过NuGetpackagemanager命令行工具输入以下命令:
dotnetaddpackageSystem.Threading.Channels
创建channel
本质上来说,你可以创建两种类型的channel,一种是有限容量的boundchannel,一种是无限容量的unboundchannel,接下来的问题是,如何创建呢?Channels提供了两种工厂方法用于创建,如下代码所示:
- CreateBounded
创建的channel是一个有消息上限的通道。 - CreateUnbounded
创建的channel是一个无消息上限的通道。
下面的代码片段展示了如何创建unboundedchannel,并且只能存放string类型。
staticvoidMain(string[]args) { varchannel=Channel.CreateUnbounded(); }
对了,Boundedchannel还提供了一个FullMode属性,用于指定当channel已满时该如何对插入的message进行处理,通常有四种做法。
- Wait
- DropWrite
- DropNewest
- DropOldest
下面的代码片段展示了如何在Boundedchannel上使用FullMode。
staticvoidMain(string[]args) { varchannel=Channel.CreateBounded(newBoundedChannelOptions(1000) { FullMode=BoundedChannelFullMode.Wait }); }
将消息写入到channel
要想将message写入到channel,可以使用WriteAsync()方法,如下代码所示:
staticasyncTaskMain(string[]args) { varchannel=Channel.CreateBounded(newBoundedChannelOptions(1000) { FullMode=BoundedChannelFullMode.Wait }); awaitchannel.Writer.WriteAsync("HelloWorld!"); }
从channel中读取消息
要想从channel中读取message,可以使用ReadAsync(),如下代码所示:
staticasyncTaskMain(string[]args) { varchannel=Channel.CreateBounded(newBoundedChannelOptions(1000) { FullMode=BoundedChannelFullMode.Wait }); while(awaitchannel.Reader.WaitToReadAsync()) { if(channel.Reader.TryRead(outvarmessage)) { Console.WriteLine(message); } } }
System.Threading.Channels例子
下面是完整的代码清单,展示了如何从channel中读写message。
classProgram { staticasyncTaskMain(string[]args) { awaitSingleProducerSingleConsumer(); Console.ReadKey(); } publicstaticasyncTaskSingleProducerSingleConsumer() { varchannel=Channel.CreateUnbounded(); varreader=channel.Reader; for(inti=0;i<10;i++) { awaitchannel.Writer.WriteAsync(i+1); } while(awaitreader.WaitToReadAsync()) { if(reader.TryRead(outvarnumber)) { Console.WriteLine(number); } } } }
可以看到,控制台中输出了数字1-10,这些数字正是Writer写入到channel中的,对吧。
总的来说,要想使用生产者-消费者场景,有几种实现途径,比如:BlockingCollection和TPLDataflow,但本篇介绍的Channels要比前面的两种性能更高,关于Channels更多的细节,我会在未来的文章中进行讨论,如果您现在想急于了解的话,可以参考MSDN:https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels?view=netcore-3.0
总结
到此这篇关于在C#中使用Channels的文章就介绍到这了,更多相关C#使用Channels内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。