- using System.Threading;
- namespace Threadsss
- {
- class Program
- {
- static void ThreadMethod(object state)
- {
- Console.WriteLine("线程开始:"+ Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(2000);
- Console.WriteLine("线程结束");
- }
-
- static void Main(string[] args)
- {
- ThreadPool.QueueUserWorkItem(ThreadMethod);
- ThreadPool.QueueUserWorkItem(ThreadMethod);
- ThreadPool.QueueUserWorkItem(ThreadMethod);
- ThreadPool.QueueUserWorkItem(ThreadMethod);
- Console.ReadKey();
- }
- }
- }
线程池的技术背景
线程池技术如何提高服务器程序的性能
我所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:
假设在一台服务器完成一项任务的时间为T
T1 创建线程的时间 T2 在线程中执行任务的时间,包括线程间同步所需时间 T3 线程销毁的时间
显然T = T1+T2+T3。注意这是一个极度简化的假设。
可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。在看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。我们比较利用线程池技术和不利于线程池技术的服务器处理这些请求时所产生的线程总数。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目或者上限(以下简称线程池尺寸),而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池尺寸是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
有关线程池的解释请参考:
把上面的代码修改之后如下:
class Program { static void Main(string[] args) { Console.WriteLine("Begin in Main"); //Thread thread = new Thread(new ThreadStart(ThreadInvoke)); 启动线程 //thread.Start(); ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadInvoke)); //将当前线程挂起200毫秒 Thread.Sleep(200); Console.WriteLine("End in Main"); Thread.Sleep(3000); } static void ThreadInvoke(Object param) { for (int i = 0; i < 5; i++) { Console.WriteLine("Execute in ThreadInvoke"); //每隔100毫秒,循环一次 Thread.Sleep(100); } } }
输出结果:
上面的代码把线程的创建和启动改为了ThreadPool.QueueUserWorkItem(newWaitCallback(ThreadInvoke)),方法ThreadInvoke加了个参数(Object param),并在Main结束之间加了Thread.Sleep(3000);Thread.Sleep(3000)这句话是必须的因为当Main方法结束后,.Net环境会自动结束销毁线程池,为了保证完成线程池里的任务,所以主线程需要等待一段时间。
由输出结果可知,Main方法和ThreadInvoke方法是并行执行的。
- using System;
- using System.Threading;
- class Packet //定义对象类,用来包装参数,实现多个参数的传递
- {
- Protected internal String inval1;
- Protected interval String inval2;
- Protected interval String outval;
- }
- class ThreadPoolExam //定义执行相同内容的两个方法
- {
- public void Task1(object Obj)
- {
- Packet PacketObj; //声明Packet类对象,用来传递参数
- PackerObj = (Packet)Obj ;
- Console.WriteLine("任务1中的第一个参数:"+ PacketObj.inval1);
- Console.WriteLine("任务1中的第二个参数:"+ PacketObj.inval2);
- PacketObj.outval = PacketObj.inval1 + " " +PacketObj.inval2;
- }
- public void Task2(object Obj)
- {
- Packet PacketObj;
- PackerObj = (Packet)Obj ;
- Console.WriteLine("任务1中的第一个参数:"+ PacketObj.inval1);
- Console.WriteLine("任务1中的第二个参数:"+ PacketObj.inval2);
- PacketObj.outval = PacketObj.inval1 + " " +PacketObj.inval2;
- }
- static void Main()
- {
- Packet PacketObj1 = new Packet(); //声明两个Packet对象,并为输入参数赋值
- Packet PacketObj2 = new Packet();
- PacketObj1.inval1 = "这是任务1的参数1";
- PacketObj1.inval2 = "这是任务1的参数2";
- PacketObj2.inval1 = "这是任务2的参数1";
- PacketObj2.inval2 = "这是任务2的参数2";
- ThreadPoolExam tps = new ThreadPoolExam(); //以下放入线程池
-
- ThreadPool.QueueUserWorkItem(new WaitCallback(tps.Task1), PacketObj1);
- ThreadPool.QueueUserWorkItem(new WaitCallback(tps.Task2), PacketObj2);
- Console.ReadKey();
- }
- }