线程池实现的原理:
多线程单元模式,借助抢先式多任务方式,利用高性能的队列和调度来实现。
线程池管理是指多线程应用程序的初始化过程中创建线程的集合,当需要线程是,为新的任务重用线程,而不是创建新的线程。线程的数量一般是固定的。线程池中的线程都分配了一个任务,当任务完成时,线程就返回线程池中等待下一次分配。
线程池的优点:
• 不需要重新创建线程
• CLR不必为每个生存周期短暂的任务创建一个全新的线程,并在结束时回收其资源
• 线程池根据进程,优化时间片
• 启动多个线程,不必为每个线程设置属性
• 允许将线程的状态信息作为一个对象传递给当前执行任务的过程参数 WaitCallback(void (object))
• 将客户请求的线程数量固定为某一个最大值
线程池的限制:
• CLR负责维护线程池。如果任务已添加到队列中,就不能直接取消任务
• 线程池对于生存期较短的任务非常有效,但不适用于又打又长的任务
• 线程池的成本效率比根据数量和启动开销来确定。线程池的大小应该固定不变
• 线程池的所有线程都处于多线程单元中。如果把线程池放到单线程单元中,线程池就没有作用
• 线程池中的线程不能手动执行启动,挂起和终止线程
• 线程池中的线程不能指定优先级
• 一个应用程序只能有一个线程池
• 如果线程池中的一个任务被锁定,则这个线程不在会被释放到池中
测试代码
代码说明:
ThreadTest说明:
启动50线程执行LongCalculate1;启动50个线程执行LongCalculate2. LongCalculate1,LongCalculate2分别执行999次的循环,输出当前循环的次数。
ThreadPoolTest说明:
向线程池添加50次方法LongCalculateCallback1;
向线程池添加50次方法LongCalculateCallback2;
LongCalculateCallback1,LongCalculateCallback2分别执行999次的循环,输出当前循环的次数。
其中LongCalculate1,LongCalculate2,LongCalculateCallback1,LongCalculateCallback2方法体执行相同的方法。
目的:
使用性能计数器统计进程中ThreadTest,ThreadPoolTest每秒钟线程个数与进程线程使用处理器执行指令所花的时间百分比。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace NetThreading
{
/// <summary>
/// 线程池类的使用
/// </summary>
internal class ThreadPoolApp:IMain
{
/// <summary>
/// 最大线程数
/// </summary>
const int maxThreadCount = 50;
/// <summary>
/// 循环最大值
/// </summary>
const int maxCount = 999;
/// <summary>
/// 线程休眠时间
/// </summary>
const int sleepTimeSpan = 0;
/// <summary>
/// 显示线程池的相关信息
/// </summary>
private void ShowThreadPoolInfo()
{
int workerThreads,completionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads,out completionPortThreads);
Console.WriteLine("线程池中辅助线程的最大数:{0}", workerThreads);
Console.WriteLine("线程池中异步 I/O 线程的最大数目:{0}", completionPortThreads);
}
/// <summary>
/// 使用线程池创建多线程
/// </summary>
private void ThreadPoolTest()
{
for (int i = 0; i < maxThreadCount ; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(LongCalculateCallback1));
ThreadPool.QueueUserWorkItem(new WaitCallback(LongCalculateCallback2));
}
}
/// <summary>
/// 一般多线程
/// </summary>
private void ThreadTest()
{
for (int i = 0; i < maxThreadCount ; i++)
{
Thread t1 = new Thread(new ThreadStart(LongCalculate1 ));
t1.Start();
Thread t2 = new Thread(new ThreadStart(LongCalculate2));
t2.Start();
}
}
#region 调用方法
private void LongCalculate1()
{
Console.WriteLine("ThreadID:{0} LongCalculate1 Start ", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < maxCount; i++)
{
Thread.Sleep(sleepTimeSpan);
Console.WriteLine("ThreadID:{0} LongCalculate1 Running {1}", Thread.CurrentThread.ManagedThreadId,i);
}
Console.WriteLine("ThreadID:{0} LongCalculate1 end", Thread.CurrentThread.ManagedThreadId);
}
private void LongCalculate2()
{
Console.WriteLine("ThreadID:{0} LongCalculate2 Start ", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < maxCount; i++)
{
Thread.Sleep(sleepTimeSpan);
Console.WriteLine("ThreadID:{0} LongCalculate2 Running {1}", Thread.CurrentThread.ManagedThreadId,i);
}
Console.WriteLine("ThreadID:{0} LongCalculate2 end", Thread.CurrentThread.ManagedThreadId);
}
private void LongCalculateCallback1(object obj)
{
Console.WriteLine("ThreadID:{0} LongCalculateCallback1 Start ", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < maxCount; i++)
{
Thread.Sleep(sleepTimeSpan);
Console.WriteLine("ThreadID:{0} LongCalculateCallback1 Running {1}", Thread.CurrentThread.ManagedThreadId,i);
}
Console.WriteLine("ThreadID:{0} LongCalculateCallback1 end", Thread.CurrentThread.ManagedThreadId);
}
private void LongCalculateCallback2(object obj)
{
Console.WriteLine("ThreadID:{0} LongCalculateCallback2 Start ", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < maxCount; i++)
{
Thread.Sleep(sleepTimeSpan);
Console.WriteLine("ThreadID:{0} LongCalculateCallback2 Running {1}", Thread.CurrentThread.ManagedThreadId,i );
}
Console.WriteLine("ThreadID:{0} LongCalculateCallback2 end", Thread.CurrentThread.ManagedThreadId);
}
#endregion
#region IMain 成员
public void MainRun()
{
ShowThreadPoolInfo();
//ThreadTest();
ThreadPoolTest();
}
#endregion
}
}
运行结果:
线程池相关的默认信息
2 ThreadPoolTest运行结果
结论
线程个数:
方法名称 | 最大线程数 | 最小线程数 | 平均线程数 |
ThreadTest | 115 | 22 | 71 |
ThreadPoolTest | 18 | 11 | 17 |
线程使用处理器执行指令所花的时间百分比:(注意100%表示为150%)
方法名称 | 最大 | 最小 | 平均 |
ThreadTest | 110 | 0 | --- |
ThreadPoolTest | 138 | 0 | ---- |
ThreadPool可以减少应用的线程数,也可以减少应用程序对cpu时间的占用。
但是把sleepTimeSpan调大后,使用线程池的的程序产生线程数呈增大趋势。这是为什么呢?