在 C# 中处理任务队列:面向初学者
\n\n在现代开发中,经常需要在不阻塞应用程序主线程的情况下处理大量任务。想象一下一个必须同时响应数百名用户的网络服务器,或者一个处理文件上传的后台服务。在这种情况下,任务队列(task queue)——一种基础的数据结构和编程模式——就派上了用场。
\n\n在本文中,我们将通过实际示例,从基础类到多线程应用程序的线程安全解决方案,详细讲解 C# (.NET) 中任务队列的工作原理。
\n\n什么是任务队列,为什么需要它?
\n\n队列(Queue)是一种遵循 FIFO(先进先出)原则的数据结构:第一个添加的元素将首先被处理。在任务的上下文中,这意味着我们可以将任务放入队列,并在资源空闲时稍后处理它。
\n\n任务队列的主要使用场景:
\n- \n
- 后台处理(发送电子邮件、生成报告) \n
- 负载均衡(在工作线程之间分配任务) \n
- 请求缓冲(当系统无法立即处理所有请求时) \n
- 异步日志记录(在不减慢主应用程序的情况下写入日志) \n
C# 中的基础类 Queue<T>
\n\n.NET 中有一个内置类 Queue<T>,位于 System.Collections.Generic 命名空间中。让我们看一个最简单的例子:
using System;\nusing System.Collections.Generic;\n\npublic class SimpleQueueExample\n{\n public static void Main()\n {\n // 创建一个字符串队列\n Queue<string> taskQueue = new Queue<string>();\n\n // 添加任务\n taskQueue.Enqueue("发送邮件给客户");\n taskQueue.Enqueue("生成报告");\n taskQueue.Enqueue("更新缓存");\n\n Console.WriteLine($"队列中的任务数量: {taskQueue.Count}");\n\n // 按顺序处理任务\n while (taskQueue.Count > 0)\n {\n string task = taskQueue.Dequeue();\n Console.WriteLine($"处理中: {task}");\n }\n\n Console.WriteLine($"队列为空: {taskQueue.Count == 0}");\n }\n}\n\nQueue<T> 的主要方法:
- \n
Enqueue(T item)— 将元素添加到队列末尾 \n Dequeue()— 从队列开头取出并移除元素 \n Peek()— 返回第一个元素但不移除它 \n Count— 队列中的元素数量 \n
重要提示: Queue<T> 不是线程安全的。如果多个线程同时读写队列,将会出现错误。对于多线程场景,请使用 ConcurrentQueue<T>。
线程安全队列:ConcurrentQueue<T>
\n\n在实际应用中,任务队列几乎总是在多线程环境中使用。为此,.NET 提供了 ConcurrentQueue<T>,位于 System.Collections.Concurrent 命名空间中。
using System;\nusing System.Collections.Concurrent;\nusing System.Threading.Tasks;\n\npublic class ConcurrentQueueExample\n{\n public static void Main()\n {\n ConcurrentQueue<string> taskQueue = new ConcurrentQueue<string>();\n\n // 任务 1:添加元素(生产者)\n Task producer = Task.Run(() =>\n {\n for (int i = 1; i <= 10; i++)\n {\n taskQueue.Enqueue($"任务 #{i}");\n Console.WriteLine($"已添加任务 #{i}");\n