前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >.NET 中 Channel 类简单使用

.NET 中 Channel 类简单使用

作者头像
MJ.Zhou
发布于 2024-05-21 00:04:16
发布于 2024-05-21 00:04:16
18600
代码可运行
举报
文章被收录于专栏:.NET开发那点事.NET开发那点事
运行总次数:0
代码可运行

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 类来创建一个生产者-消费者模型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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 参数指定了通道的容量。当通道满时,尝试写入的操作将会阻塞,直到有空间可用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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 后新加入的类。为我们提供了便利的生产者/消费者模式实现方案。相当于是一个进程内的内存队列,而且它没有持久化,纯内存操作,性能是非常非常高的。当我们面对真正的高并发的时候可以为我们的系统提供吞吐量。当然代价是内存跟放弃一些实时性。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# Channels
通过使用异步编程,我们可以提高应用程序的响应性和吞吐量。C# 提供了一些内置的方案来处理异步编程,例如 async/await 关键字和 Task 类。然而,有时候我们需要处理更复杂的场景,比如处理流式数据或者实现生产者/消费者模型。这就是为什么 .NET Core 3.0 引入了 System.Threading.Channels 的地方。
JusterZhu
2023/11/27
4770
C# Channels
Channels: C# 实现高效的线程间通信
在C#中,Channel是.NET Core 3.0及更高版本引入的一种新的集合类型,位于System.Threading.Channels命名空间下。主要用于实现生产者-消费者模式,支持异步编程、高性能和线程安全。
郑子铭
2025/04/22
2160
Channels: C# 实现高效的线程间通信
编程语言.NET 进程内队列 Channel 的入门与应用
最近,博主为 FakeRPC[1] 增加了 WebSocket[2] 协议的支持。这意味着,我们可以借助其全双工通信的特性,在一个连接请求内发送多条数据。FakeRPC 目前最大的遗憾是,建立在 HTTP 协议上而不是 TCP/IP 协议上。因此,考虑 WebSocket 协议,更多的是为了验证 JSON-RPC[3] 的可行性,以及为接下来的要支持的 TCP/IP 协议铺路。也许,你从未意识到这些概念间千丝万缕的联系,可如果我们把每一次 RPC 调用都理解为一组消息,你是不是就能更加深刻地理解 RPC 这个稍显古老的事物了呢?在编写 FakeRPC 的过程中,我使用了 .NET 中的全新数据结构 Channel 来实现消息的转发。以服务端为例,每一个 RPC 请求经过 CallInvoker 处理以后,作为 RPC 响应的结果其实并不是立即发回给客户端,而是通过一个后台线程从 Channel 取出消息再发回客户端。 那么,博主为什么要舍近求远呢?我希望,这篇文章可以告诉你答案。
郑子铭
2024/01/03
4210
编程语言.NET 进程内队列 Channel 的入门与应用
一文读懂 .NET 中的高性能队列 Channel
System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能,线程安全等特点,它可以用来做消息队列,进行数据的生产和消费, 公开的 Writer 和 Reader api对应消息的生产者和消费者,也让Channel更加的简洁和易用,与Rabbit MQ 等其他队列不同的是,Channel 是进程内的队列。
全球技术精选
2021/07/23
2.5K0
一文读懂 .NET 中的高性能队列 Channel
.NET隐藏王牌:揭秘速度提升25倍的高性能通道实战
这就是通道(Channels)——一种实现组件间异步消息传递的超高效方式。尽管性能惊人,许多开发者仍未充分利用它。本文将深入解析通道的原理、优势,并通过真实案例演示如何快速上手。
郑子铭
2025/06/07
940
.NET隐藏王牌:揭秘速度提升25倍的高性能通道实战
C#开发者必知的100个黑科技(后50)!从主构造函数到源生成器全面掌握
郑子铭
2025/05/17
660
C#开发者必知的100个黑科技(后50)!从主构造函数到源生成器全面掌握
.NET Core 使用 System.Threading.Channels消息队列
System.Threading.Channels 是 .NET Core 中的一个新的同步通信机制,它提供了一种高效的方法来在多个线程之间共享数据。它比使用锁或信号量等传统同步机制更灵活、更高效,并且可以帮助您避免许多并发问题。下面是一个简单的示例,演示如何使用 Channels 实现生产者-消费者模型。
喵叔
2023/11/04
8150
.NET Core 使用 Channel 消息队列
最近做一个项目,连接了很多设备,需要保存设备的心跳数据,刚开始的做法是直接接收到设备的数据之后进行心跳数据的保存,但是随着设备多了起来,然后设备的使用时长不断的加大,对数据库的压力也比较大,所以想着优化一下。
郑子铭
2023/08/30
6940
.NET Core 使用 Channel 消息队列
两种基于时间窗口的限流器的简单实现
之前开发的一款基于OpenTelemetry的Tracing组件需要使用基于速率限制(Rate Limiting)的跟踪采样策略,本想使用现有的解决方案,比如System.Threading.RateLimiting命名空间下的RateLimiter。大体看了RateLimiter的三种实现(固定窗口、滑动窗口和令牌桶),觉得过于相对复杂了点,代码还涉及到锁,而且提供的功能我也不太需要,于是尝试实现一种简单且无锁解决方案。
蒋金楠
2023/11/02
3550
两种基于时间窗口的限流器的简单实现
C#学习笔记 线程同步问题
生产者消费者问题大体是这样的:有几个生产者和几个消费者,共享一个缓冲区。生产者会向缓冲区中添加数据;消费者会从缓冲区中将数据取走。需要处理这两者之间的同步问题。
乐百川
2022/05/05
4060
【数据传输】进程内业务拆分的数据传输,可用于发布订阅或者传递通知。
          又是两个月没有写博客了,也有一个月没有玩单片机做手工学习了;前几天在某个群里看到,有个群友说自己用了个内存队列用来保存某个task的数据,然后在某一处又使用死循环来判断内存队列的数据是否大于0,针对这个问题,才引发了这一边博客,哈哈,之前看到过有些人碰到这种场景是开线程使用死循环来进行数据传输处理。其实针对这个问题,while并不算是一个很好的解决方案,具体的还得结合场景去进行判断如何找到最优的解决方案,在本篇博客,我会罗列出我所已知和这个议题相关的几种方案,以及写了的部分代码。
陈显达
2022/11/07
5170
.NET 各版本多线程使用原理与实践
多线程编程是现代应用程序开发中的核心技术,尤其是在需要并发处理或提升性能的场景中。本文将以 .NET 各版本为背景,详细探讨多线程技术的发展、底层原理以及实践方法。
Michel_Rolle
2024/11/19
2.9K0
C# BufferBlock
BufferBlock是C#中的一个数据流块(Dataflow Block),它提供了一个有界或无界的缓冲区,用于存储数据。类似于BlockingCollection,你可以使用Post方法往BufferBlock中添加数据,也可以通过Receive方法阻塞或异步地读取数据。在高性能方面,BufferBlock是C#中一种常用的选择。
JusterZhu
2023/10/24
3910
C#  BufferBlock
C#的Task 和 Task<T>
在C#中,Task和Task<T>是实现异步编程的核心类型。它们允许开发者编写非阻塞代码,从而提高应用程序的响应性和吞吐量。本文将深入探讨C#中的Task和Task<T>,包括它们的基本概念、实现方式、高级用法和最佳实践。
Michel_Rolle
2024/10/08
3K0
Asp.Net Core 轻松学-多线程之Task快速上手
    Task是从 .NET Framework 4 开始引入的一项基于队列的异步任务(TAP)模式,从 .NET Framework 4.5 开始,任何使用 async/await 进行修饰的方法,都会被认为是一个异步方法;实际上,这些异步方法都是基于队列的线程任务,从你开始使用 Task 去运行一段代码的时候,实际上就相当于开启了一个线程,默认情况下,这个线程数由线程池 ThreadPool 进行管理的。
梁规晓
2019/04/11
1.6K0
Asp.Net Core 轻松学-多线程之Task快速上手
C#的async 和 await 关键字
在C#中,async和await关键字是实现异步编程的核心工具。它们允许开发者编写非阻塞的代码,从而提高应用程序的响应性和吞吐量。本文将深入探讨C#中的async和await关键字,包括它们的基本概念、实现方式、高级用法和最佳实践。
Michel_Rolle
2024/10/08
3K0
.NET Core多线程 (3) 异步 - 下
方法一:不使用同步上下文(比如WindowsFormSynchronizationContext)
Edison Zhou
2023/08/11
2860
.NET Core多线程 (3) 异步 - 下
c#异步编程-Task(二)
大家好,本次继续分享自己的学习经历。本文主要分享Task异步编程内容,如果能帮助大家希望多多关注文章末尾的微信公众号和知乎三连。各位举手之劳是对我更新技术文章最大的支持。
JusterZhu
2022/12/07
2.6K0
c#异步编程-Task(二)
C# 如何实现一个事件总线
Event Bus(事件总线)是一种用于在应用程序内部或跨应用程序组件之间进行事件通信的机制。
郑子铭
2024/01/17
3270
C# 如何实现一个事件总线
C#的线程
多线程编程是现代软件开发中的一项关键技术,它允许程序同时执行多个任务,从而提高应用程序的响应性和性能。C#提供了丰富的线程管理功能,包括线程的创建、同步、通信和池化等。本文将深入探讨C#中线程的工作原理、使用场景、最佳实践以及一些高级技巧。
Michel_Rolle
2024/10/09
3K0
相关推荐
C# Channels
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验