1.线程池介绍
线程池是一种软件设计模式,用于管理和复用线程资源,以提高程序性能和资源利用率。线程池的设计会预先创建一定数量的线程,并将这些线程置于一个池中等待任务分配,而不是为每个新任务单独创建线程。
2.线程池的工作原理:
- 线程创建:线程池在初始化时会创建一定数量的线程,并将其置于就绪状态等待任务。
- 任务队列:当有新任务提交到线程池时,它们会被放置在一个内部的任务队列中。
- 任务分配:线程池中的线程会从任务队列中取出任务并执行。如果所有线程都在忙碌,新来的任务会排队等待,直到有线程可用。
- 线程复用:线程在完成一个任务后,并不会销毁,而是返回线程池等待下一个任务,从而减少了创建和销毁线程的开销。
- 动态调整:根据需要,线程池可以动态调整线程数量,例如,在任务队列积压较多时增加线程,或者在系统资源紧张时减少线程。
- 饱和策略:当线程池达到其最大线程数,且任务队列也已满时,对于新来的任务,线程池会执行预定义的饱和策略,如拒绝任务、丢弃旧任务等。
3. C#中的线程池实现:
3.1使用ThreadPool
类
- 通过
ThreadPool.QueueUserWorkItem
方法将工作项排队到线程池中执行。这种方法直接操作线程池,但不提供直接的异步编程模型,也不便于管理和取消任务。
using System;
using System.Threading;
class ThreadPoolDemo
{
static void WorkerMethod(object threadContext)
{
string threadName = Thread.CurrentThread.Name;
if (threadName != null)
Console.WriteLine($"{threadName}: Working in thread pool.");
else
Console.WriteLine($"Unnamed thread: Working in thread pool.");
}
static void Main(string[] args)
{
// 设置线程池线程名称,以便识别(可选)
Thread.CurrentThread.Name = "Main Thread";
// 启动多个线程池任务
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(WorkerMethod, i);
}
Console.WriteLine("Main thread work done.");
}
}
3.2 使用Task
和async/await
在 C# 中,async
和 await
关键字用于异步编程,而 Task
类表示一个异步操作。结合 ThreadPool
可以实现异步的线程池操作。
示例代码
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Main thread starting.");
// 启动任务
Task<int> task = DoWorkAsync();
// 执行其他操作
Console.WriteLine("Doing other work in the main thread...");
// 等待任务完成并获取结果
int result = await task;
Console.WriteLine($"Result from async task: {result}");
Console.WriteLine("Main thread ending.");
}
static async Task<int> DoWorkAsync()
{
Console.WriteLine("Starting async work...");
// 使用线程池运行计算密集型操作
int result = await Task.Run(() =>
{
Thread.Sleep(2000); // 模拟长时间运行的任务
return 42; // 模拟计算结果
});
Console.WriteLine("Async work completed.");
return result;
}
}
解释
-
Main
方法:Main
方法是应用程序的入口点。使用async Task
而不是void
使得Main
方法能够使用await
关键字。DoWorkAsync
方法被调用并返回一个Task<int>
,代表异步操作。
-
DoWorkAsync
方法:DoWorkAsync
是一个异步方法,返回一个Task<int>
。- 使用
await Task.Run()
将计算密集型操作卸载到线程池,以避免阻塞主线程。 Task.Run
方法会在线程池中启动一个新任务,并立即返回一个表示该任务的Task
对象。
-
Task.Run
:Task.Run
方法用于在线程池中异步执行指定的操作。在这个例子中,操作是一个简单的 lambda 表达式,其中包含Thread.Sleep(2000)
模拟长时间运行的任务。Thread.Sleep(2000)
阻塞当前线程 2 秒钟,模拟计算密集型任务。
-
使用
await
:await
关键字等待异步任务完成,而不会阻塞主线程。它使得异步方法可以在任务完成后继续执行。
-
结果处理:
- 一旦异步任务完成,
await
表达式返回结果,并继续执行后续代码。
- 一旦异步任务完成,
关键点
async
和await
: 用于声明和使用异步方法。async
关键字用于方法声明,await
关键字用于等待异步任务完成。Task
: 表示一个异步操作,可以返回一个值或不返回值(Task
或Task<T>
)。Task.Run
: 将工作卸载到线程池中,以避免阻塞调用线程。- 线程池: 由系统管理的一组线程,用于执行异步任务,避免了创建和销毁线程的开销。