C#队列Queue详解

一问题

假设:

你在做上位机。

有两个线程:


线程1(PLC采集线程)

不停读取PLC:

复制代码
每10ms读取一次数据

线程2(数据库线程)

负责保存数据:

复制代码
保存一次需要100ms

问题来了

PLC数据来的速度:

复制代码
远远快于数据库保存速度

怎么办?

二解决办法:队列缓冲

先存起来,搞一个队列出来,PLC线程只负责采集数据,然后放入队列,数据库线程,慢慢从队列中取数据,保存到数据库

这就是生产者消费者模型

三普通队列Queue

3.1.场景

平常存数据用,集合,数组,数据库都是随便查,随便删,随机访问。

而队列不支持随机访问,只能先进先出

场景1:消息排队

  • 聊天消息接收
  • 订单处理
  • 日志写入
  • 后台任务排队
  • 游戏技能释放队列

场景 2:广度优先搜索 BFS(算法)

比如迷宫寻路、层级遍历,必须用队列。

场景 3:异步任务排队

比如:

  • 上传文件队列
  • 打印队列
  • 接口请求限流队列

这些都是必须排队的业务。

3.2特点

  • 只能从尾部加数据
  • 只能从头部取数据
  • 不能随机访问(不能取第 3 个、第 5 个)
  • 按顺序处理
  • 内部自动扩容
  • 配合 BFS(广度优先)必用

3.3核心方法

方法 作用
Enqueue(item) 把数据加到队尾
Dequeue() 取出并删除队首数据
Peek() 查看队首,但不删除
Clear() 清空队列
Contains(item) 判断是否包含某个数据

额外常用:

  • Count:队列里有多少个数据

3.4实例

cs 复制代码
// 1. 创建队列
Queue<string> queue = new Queue<string>();

// 2. 入队(加到尾部)
queue.Enqueue("第1个人");
queue.Enqueue("第2个人");
queue.Enqueue("第3个人");

// 现在队列:第1 → 第2 → 第3


// 3. 查看队首(不删除)
string first = queue.Peek(); 
Console.WriteLine(first); // 输出:第1个人


// 4. 出队(取出并删除队首)
string a = queue.Dequeue(); // 取出:第1个人
string b = queue.Dequeue(); // 取出:第2个人

// 现在队列只剩:第3个人


// 5. 遍历队列(不会删除数据)
foreach(var item in queue)
{
    Console.WriteLine(item);
}

四多线程安全队列ConcurrentQuenue

4.1用途

ConcurrentQueue = 线程安全的队列 专门给多线程、并发场景用的。

如果:

  • 线程 A:往队列加数据
  • 线程 B:从队列取数据

普通 Queue 会直接崩溃、数据丢失、卡死

ConcurrentQueue 就是为了解决这个问题诞生的!

4.2特点

  1. 线程安全
  2. 先进先出
  3. 无锁/轻量级锁
  4. 不能修改中间元素
  5. 不能随机访问
  6. 配合多线程BFS也能用

4.3核心方法

方法 作用
Enqueue(item) 加到队尾(和普通 Queue 一样)
TryDequeue(out item) 尝试取出队首,并删除(安全取出)
TryPeek(out item) 尝试查看队首,不删除
IsEmpty 判断队列是否为空
Count 元素数量(不推荐频繁用)

**为什么带 Try?**多线程时,可能刚好被别的线程取走了,所以要 "尝试取"。

4.4实例

cs 复制代码
// 1. 创建并发队列
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();

// 2. 入队(和普通一样)
queue.Enqueue(10);
queue.Enqueue(20);
queue.Enqueue(30);

// 3.  Try 取出队首(安全!)
if (queue.TryDequeue(out int result))
{
    Console.WriteLine("取出:" + result); // 10
}

// 4. Try 查看队首(不删除)
if (queue.TryPeek(out int first))
{
    Console.WriteLine("队首是:" + first); // 20
}

// 5. 判断空
bool empty = queue.IsEmpty;

4.5场景实例

cs 复制代码
// 并发队列
ConcurrentQueue<string> taskQueue = new ConcurrentQueue<string>();

// 生产者线程:往队列加任务
Task.Run(() =>
{
    for (int i = 1; i <= 5; i++)
    {
        taskQueue.Enqueue("任务" + i);
        Console.WriteLine("生产:任务" + i);
        Task.Delay(300).Wait();
    }
});

// 消费者线程:从队列取任务
Task.Run(() =>
{
    while (true)
    {
        if (taskQueue.TryDequeue(out string task))
        {
            Console.WriteLine("处理:" + task);
        }
        Task.Delay(200).Wait();
    }
});

Console.ReadLine();
相关推荐
LDR00612 小时前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术12 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园12 小时前
C++20 Modules 模块详解
java·开发语言·spring
swordbob12 小时前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
源分享13 小时前
Java线程同步的多种实现方法(非常详细)
java·开发语言·jvm
Luminous.13 小时前
C语言--day30
c语言·开发语言
何以解忧,唯有..13 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
謓泽13 小时前
C语言不是语法,是通往机器的地图。
c语言·开发语言
云水一下13 小时前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
麦聪聊数据13 小时前
数据服务化时代:企业数据能力输出的核心路径
数据库