• C# Channel 简单实现消息队列的发布、订阅


    十年河东,十年河西,莫欺少年穷

    学无止境,精益求精

    这里需要声明的是:

    虽说 Channel 类似于 MQ ,但 Channel 并不支持跨项目使用,MQ 作为中间件,它里面的消息可以被多个项目共享,但  Channel 中的消息只能用于单体项目中共享。

    介绍

    首先,Channel本质上是.net中的一种新的集合类型,它与现有的Queue<T>类型非常相似,当然也有不同之处。

    System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能,线程安全等特点,它可以用来做消息队列,进行数据的生产和消费, 公开的 WriterReader api对应消息的生产者和消费者,也让Channel更加的简洁和易用,与Rabbit MQ 等其他队列不同的是,Channel 是进程内的队列。

    为什么要使用 Channels

    可以利用 Channels 来实现 生产者和消费者 之间的解耦,大体上有两个好处:

    • 生产者 和 消费者 是相互独立的,两者可以并行执行。

    • 如果生产者不给力,可以创建多个的生产者,如果消费者不给力,可以创建更多的消费者。

    总的来说,在 生产者-消费者 模式下可以帮助我们提高应用程序的吞吐率。

    创建Channel 

    nuget 中搜索 Channel 并安装

    channel 分为固定容量的,和无限容量的

    无限容量的Channel创建

                //无限容量的
                var channel_1 = Channel.CreateUnbounded<msgDto>();
    
                var channel_2 = Channel.CreateUnbounded<string>(new UnboundedChannelOptions()
                {
                    SingleWriter = false, //允许一次写入多个消息
                    SingleReader = true //一次只能读取一条消息
                });

    CreateUnbounded<T> 是指消息的类型,可以为简单的 int 、string 类型,也可以定义成一个类,上述的 msgDto 就是一个简答的类

        public class msgDto
        {
            public string msgid { get; set; }
            public string msg { get; set; }
        }

    有限容量的Channel创建

                //限容Channel  
                var channel_3 = Channel.CreateBounded<string>(10000);
                var channel_4 = Channel.CreateBounded<msgDto>(new BoundedChannelOptions(100)
                {
                    FullMode = BoundedChannelFullMode.Wait, //消息满了 等待消费 新的消息不插入
                    SingleWriter = false,//允许一次写入多条数据
                    SingleReader = false,//允许一次读取多条数据
    
                });

    注意,BoundedChannelFullMode 共有四种

    • Wait                   等待空间可用以便完成写入操作。

    • DropWrite          删除要写入的项。

    • DropNewest      删除并忽略通道中的最新项,以便为要写入的项留出空间。

    • DropOldest        删除并忽略通道中的最旧项,以便为要写入的项留出空间。

    生产/消费数据

            static async Task Main(string[] args)
            {
                //Channel 属于线程安全的集合
                var channel_1 = Channel.CreateUnbounded<string>(new UnboundedChannelOptions()
                {
                    SingleWriter = false, //允许一次写入多条数据,下面的Parallel.For属于多线程写入
                    SingleReader = false
                });
                //多线程写入 
                Parallel.For(0, 10, i =>
                {
                    channel_1.Writer.WriteAsync ("hello_" + i);
    
                });
    
                //消费数据
                while (await channel_1.Reader.WaitToReadAsync())
                {
                    if (channel_1.Reader.TryRead(out var message))
                    {
                        Console.WriteLine(message);
                    }
                }
    
                Console.Read();
            }

    WaitToReadAsync是一个非阻塞等待,在有消息可读或Channel关闭时,才会唤醒并继续。

    考虑到有多个消费者的情况,有可能别的线程已经进行了读取,这儿使用TryRead进行读取操作。

    要注意:数据的同步工作是由Channel进行管理的。Channel会确保多个消费者不会读到相同的数据。Channel同时也管理数据的次序。

    上述例子的输出结果:

     因为是异步多线程写入,因此,不保证顺序,但读取时,还是按照写入的顺序进行读取的。

    参考:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.channels.boundedchannelfullmode?view=net-6.0

    @天才卧龙的波尔卡 

  • 相关阅读:
    js 置顶操作
    js input输入数量控制
    js 时间倒计时
    html内容垂直居中
    大图片随浏览器水平居中显示
    img,display:inline相关间隙样式问题
    js淡入淡出轮换思想(1)
    js 禁止|阻止滚动条滚动
    kotlin学习--第一个kotlin项目
    jdk8+Mybatis3.5.0+Mysql读取LongBlob失败
  • 原文地址:https://www.cnblogs.com/chenwolong/p/Channel.html
Copyright © 2020-2023  润新知