你可能早已听说过async、await任务等概念,但在多线程间安全传输数据时,大多数人还是给List
这是C#通道系列教程的第一部分,记得订阅以便接收后续更新。
可以把Channel想象成线程安全的邮箱:一端投递信件,另一端取出信件。无需锁机制,天生支持异步操作。
本文将深入浅出,展示生产者如何轻松向消费者传递消息,既不费力也不消耗CPU。读完本篇,你不仅能掌握Channel的工作原理,还能为后续更复杂的模式打下基础。
Channel的诞生背景
坦白说,如果你用C#编写多线程代码,大概率曾与ConcurrentQueue、BlockingCollection纠缠过,或手动给List
Channel优雅地解决了这些问题,它提供:
就像现实中的邮箱,一端投信另一端取信,即使多线程同时操作也不会引发混乱。
核心概念模型 接触代码前,先建立最简心智模型: 生产者 → Channel → 消费者
后续我们会扩展至多生产者/消费者场景,目前先聚焦单读写器模式。
创建Channel .NET让通道创建变得轻而易举:
using System;
using System.Threading.Channels;
using System.Threading.Tasks;
var channel = Channel.CreateUnbounded<int>(); // 无边界通道
Console.WriteLine("Channel created!");
仅需一行代码,你就获得了可用的通信邮箱。现在你拥有了包含两个核心组件的Channel
写入Channel 来看生产者的实际运作:
async Task ProduceAsync(ChannelWriter<int> writer)
{
for (int i = 1; i <= 5; i++)
{
await writer.WriteAsync(i); // 将数据存入通道
Console.WriteLine($"Produced: {i}");
await Task.Delay(500); // 模拟工作负载
}
writer.Complete(); // 发出完成信号
}
注意:
读取Channel 消费者端的实现:
async Task ConsumeAsync(ChannelReader<int> reader)
{
await foreach (var item in reader.ReadAllAsync())
{
Console.WriteLine($"Consumed: {item}");
}
}
关键特性:
完整示例 以下是整合生产者与消费者的最小控制台程序:
using System;
using System.Threading.Channels;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var channel = Channel.CreateUnbounded<int>();
var producer = ProduceAsync(channel.Writer);
var consumer = ConsumeAsync(channel.Reader);
await Task.WhenAll(producer, consumer);
}
static async Task ProduceAsync(ChannelWriter<int> writer)
{
for (int i = 1; i <= 5; i++)
{
await writer.WriteAsync(i);
Console.WriteLine($"Produced: {i}");
await Task.Delay(500); // 模拟工作负载
}
writer.Complete();
}
static async Task ConsumeAsync(ChannelReader<int> reader)
{
await foreach (var item in reader.ReadAllAsync())
{
Console.WriteLine($"Consumed: {item}");
}
}
}
运行后将看到数字几乎同步被生产和消费。这个简洁优雅的示例完美诠释了核心概念。
实践练习 请尝试:
这将帮助你巩固"生产者→通道→消费者"的基础模式。
核心要点
恭喜!你已成功通过Channel传递首条消息,且未使用任何锁机制或担心线程安全。你已见识到生产者如何异步传递数据给消费者,理解了ChannelWriter与ChannelReader的协同工作机制,也明确了调用Complete()的重要性。
这就像搭建自己的传送带:物品从一端进入,从另一端送出,全程无需人工干预。初级阶段最重要的是保持简单:单生产者、单消费者、流畅传输。后续我们将增加更多操作员,处理反压机制,探索让Channel在真实.NET应用中大放异彩的高级异步模式。