.NET 中实现生产者-消费者模型,BlockingCollection<T> 和 Channel<T>使用示例

一、方案对比:不同线程安全集合的适用场景

二、推荐方案及示例代码

方案 1:使用 BlockingCollection(同步模型)

csharp 复制代码
public class QueueDemo
{
    private readonly BlockingCollection<int> _blockingCollection = new BlockingCollection<int>();

    private readonly CancellationTokenSource _cts = new CancellationTokenSource();

    public QueueDemo()
    {
    }

    // 生产者方法
    public void ProduceData()
    {
        Task.Run(() =>
        {
            var rnd = new Random();
            while (!_cts.IsCancellationRequested)
            {
                var item = rnd.Next(1, 100);

                _blockingCollection.Add(item);      // 触发消费者唤醒

                Console.WriteLine($"Produced1: {item}");
                Thread.Sleep(500); // 模拟生产间隔

                //if(DateTime.Now > Convert.ToDateTime("2025-02-05 16:28:00")) break;
            }

            _blockingCollection.CompleteAdding(); // 结束消费
        });
    }

    // 消费者方法
    public void ConsumeData()
    {
        // 方式1:阻塞消费(推荐)
        Task.Run(() =>
        {
            try
            {
                Thread.Sleep(1000);
                // 使用阻塞方式消费(自动处理空队列等待)
                foreach (var item in _blockingCollection.GetConsumingEnumerable(_cts.Token))
                {

                    // 自动等待新数据
                    Console.WriteLine($"Consumed from BlockingCollection: {item}, 当前个数:{_blockingCollection.Count}");
                }
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Consumption canceled");
            }
        });
    }

    // 停止所有操作
    public void Stop()
    {
        _cts.Cancel();
    }
}

//使用示例
var demo = new QueueDemo();
demo.ProduceData();
demo.ConsumeData();

Console.WriteLine("Press any key to stop...");
Console.ReadKey();

demo.Stop();

方案 2:使用 Channel(异步模型 - 推荐)

csharp 复制代码
public class ChannelDemo
{
    private readonly Channel<int> _channel = Channel.CreateUnbounded<int>(
        new UnboundedChannelOptions { SingleWriter = false, SingleReader = false }
    );

    private readonly CancellationTokenSource _cts = new CancellationTokenSource();

    // 生产者(异步写入)
    public async Task ProduceAsync()
    {
        while (true)
        {
            var item = GenerateItem();
            await _channel.Writer.WriteAsync(item); // 非阻塞写入
            Console.WriteLine($"Produce: {item}");
            await Task.Delay(20);
        }
    }

    // 消费者(异步读取)
    public async Task ConsumeAsync()
    {
        while (await _channel.Reader.WaitToReadAsync())
        {
            if (_channel.Reader.TryRead(out var item))
            {
                await ProcessItemAsync(item);
            }
        }
    }

    private int GenerateItem() => new Random().Next(1, 100);
    private async Task ProcessItemAsync(int item)
    {
        await Task.Delay(100); // 模拟异步处理
        Console.WriteLine($"Processed: {item}");
    }

    // 停止所有操作
    public void Stop()
    {
        _cts.Cancel();
    }
}

三、选型建议

相关推荐
铅笔侠_小龙虾15 小时前
Rust 学习(8)-切片类型
学习·rust·c#
牧濑红莉1 天前
网络安全竞赛pwn全解及第一道ai的wp
javascript·.net
习明然1 天前
我的本地化AI项目(三)
人工智能·python·electron·c#·avalonia
范小多1 天前
C#获取和风天气数据
java·开发语言·python·c#
z落落1 天前
C# Task WaitAll、WaitAny、WhenAll、WhenAny
开发语言·c#
玖玥拾1 天前
C# 语言进阶(十四)Unity UI界面开发 + 网络消息联动
服务器·开发语言·网络·ui·unity·c#·游戏引擎
czhc11400756632 天前
712:Atta. cursor;ToggleButton
c#
AI行业学习2 天前
OpenAI Codex 完整下载 & 安装指南(2026最新版)
linux·开发语言·python·.net·notepad++
玖玥拾2 天前
C# 语言进阶(十三)网络 DLL 库分层设计
服务器·开发语言·网络·网络协议·c#
雪靡2 天前
WPF PerMonitorV2 下的跨窗口问题
c#·wpf