自从看了老赵关于线程池的实验以后,我就想学着做一个类似的实验,验证自己的理解,现在终于做好了,请大家指正。

          一般情况下我们都使用Thread类创建线程,因为通过Thread对象可以对线程进行灵活的控制。但创建线程和销毁线程代价不菲,过多的线程会消耗掉大量的内存和CPU资源,假如某段时间内突然爆发了100个短小的线程,创建和销毁这些线程就会消耗很多时间,可能比线程本身运行的时间还长。为了改善这种状况,.NET提供了一种称之为线程池(Thread Pool)的技术。线程池提供若干个固定线程轮流为大量的任务服务,比如用10个线程轮流执行100个任务,当一个线程完成任务时,并不马上销毁,而是接手另一个任务,从而减少创建和销毁线程的消耗。

一、SetMaxThreads()的作用

    MSDN里这样解释:“检索可以同时处于活动状态的线程池请求的数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。”。这句话可真够拗口,按我的理解,就是设置线程池中所能容纳的最大线程数目,当任务数大于这个最大值时,多余的任务将在线程池外排队等候。

下面我们做个试验来验证一下,向一个线程池中排入50个线程,观察活动线程数(正在执行任务的线程,不包括空闲线程)的变化情况。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace ThreadPoolTest
{
    class Program
    {
        public static void ThreadPoolTest()
        {
            ThreadPool.SetMaxThreads(20, 20);    //线程数目上限设置为20
            ThreadPool.SetMinThreads(10, 10);    //线程数目下限设置为10

            Console.WriteLine("活动线程数	" + "线程名称	" + "状态");

            //向线程池中添加50个工作线程
            for (int i = 1; i <= 50; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(WorkFunction), i);
            }
        }

        private static object Lock = new object();
        //工作函数
        public static void WorkFunction(object n)
        {
            lock (Lock)
            {
                Console.WriteLine(GetNumberOfRuningThreads() + "		Task" + n + "		started");
            }

            //Do something
            Thread.Sleep(18681);
             
            lock (Lock)
            {
                Console.WriteLine(GetNumberOfRuningThreads() + "		Task" + n + "		finished");
            }

        }

        //获取正在执行任务的线程数
        public static int GetNumberOfRuningThreads()
        {
            int max1, max2;
            ThreadPool.GetMaxThreads(out max1, out max2);
            int available1, available2;
            ThreadPool.GetAvailableThreads(out available1, out available2);

            return (max1 - available1);
        }

        static void Main(string[] args)
        {
            ThreadPoolTest();            
                 
            Console.ReadKey();  //按下任意键结束程序       
        }
    }
}

                           

运行结果如下:

活动线程数      线程名称        状态
1                Task1           started
2                Task2           started
3                Task3           started
4                Task4           started
5                Task5           started
6                Task6           started
7                Task7           started
8                Task8           started
9                Task9           started
10              Task10          started
11              Task11          started
12              Task12          started
13              Task13          started
14              Task14          started
15              Task15          started
16              Task16          started
17              Task17          started
18              Task18          started
19              Task19          started
20              Task20          started
20              Task1           finished
20              Task21          started
20              Task3           finished
20              Task22          started
20              Task2           finished
20              Task23          started
20              Task4           finished
20              Task24          started
20              Task6           finished
20              Task25          started
20              Task8           finished
20              Task26          started
20              Task5           finished
20              Task27          started
20              Task9           finished
20              Task28          started
20              Task7           finished
20              Task29          started
20              Task10          finished
20              Task30          started
20              Task11          finished
20              Task31          started
20              Task12          finished
20              Task32          started
20              Task13          finished
20              Task33          started
20              Task14          finished
20              Task34          started
20              Task15          finished
20              Task35          started
20              Task16          finished
20              Task36          started
20              Task17          finished
20              Task37          started
20              Task18          finished
20              Task38          started
20              Task19          finished
20              Task39          started
20              Task20          finished
20              Task40          started
20              Task21          finished
20              Task41          started
20              Task22          finished
20              Task42          started
20              Task23          finished
20              Task43          started
20              Task24          finished
20              Task44          started
20              Task25          finished
20              Task45          started
20              Task26          finished
20              Task46          started
20              Task28          finished
20              Task47          started
20              Task29          finished
20              Task48          started
20              Task27          finished
20              Task49          started
20              Task30          finished
20              Task50          started
20              Task31          finished
19              Task32          finished
18              Task33          finished
17              Task34          finished
16              Task35          finished
15              Task36          finished
14              Task37          finished
13              Task38          finished
12              Task39          finished
11              Task40          finished
10              Task41          finished
9               Task42          finished
8               Task43          finished
7               Task44          finished
6               Task45          finished
5               Task46          finished
4               Task47          finished
3               Task48          finished
2               Task49          finished
1               Task50          finished

  (没想到数据这么完美,运气挺好的)

从上面的结果可以看出,线程的随着任务的增加,活动线程的数目也逐步增加,直到达到上限值20为止,之后,活动线程的数目保持不变,多余的任务在线程池外排队,当有线程完成任务时,就从排队等候的线程中取一个来执行,因此虽然任务数在变化,但线程数目保持不变。随着任务的不断完成,某一时刻,任务数少于20个,此时活动线程也开始逐步减少。

二、SetMinThreads()的作用

       MSDN中这样解释:“检索线程池在新请求预测中维护的空闲线程数。”

       这句话我也挺“专业”的,不太好懂。我的理解是:设置线程池中线程数目的下限,当任务小于下限时,不足的用空线程补足。

如何才能验证这一点呢?我首先想到的是察看总线程数目的变化情况(包括执行任务的和空闲的线程),如果总线程的最小值是MinThreads,就说明我们的猜测是正确的。但我找了半天,ThreadPool类并没有提供这样的接口,所以我们需要另想办法。

     我的办法是观察线程的创建的时间。按照设想,线程池中本来就有若干空线程,所以一开始线程开始的时间非常快。当空线程用完时,也就是当任务数量会超出线程数量时,线程池并不会立即创建新线程,而是等待大约500毫秒左右,这么做的目的是看看在这段时间内是否有其他线程完成任务来接手这个请求,这样就可以避免因创建新线程而造成的消耗。所以,后面的线程创建速度应该比较慢。

     总之一开始,创建线程的速度应该是很快的,当线程数超过下限值时,创建速度就会慢下来。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace ThreadPoolTest
{
    class Program
    {
        public static Stopwatch watch = new Stopwatch();

        public static void ThreadPoolTest()
        {
            watch.Start();

            ThreadPool.SetMaxThreads(20, 20);    //线程数目上限设置为20
            ThreadPool.SetMinThreads(10, 10);    //线程数目下限设置为10

            Console.WriteLine("时间		活动线程数	" + "线程名称	" + "状态");

            //向线程池中添加50个工作线程
              for (int i = 1; i <= 50; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(WorkFunction), i);
            }
        }

        private static object Lock = new object();
        //工作函数
         public static void WorkFunction(object n)
        {
            lock (Lock)
            {
                Console.WriteLine(watch.Elapsed + "	" + GetNumberOfRuningThreads() + "		Task" + n + "		started");
            }

            //Do something
            Thread.Sleep(38681);
             
            lock (Lock)
            {
                Console.WriteLine(watch.Elapsed + "	" + GetNumberOfRuningThreads() + "		Task" + n + "		finished");
            }

        }

        //获取正在执行任务的线程数
         public static int GetNumberOfRuningThreads()
        {
            int max1, max2;
            ThreadPool.GetMaxThreads(out max1, out max2);
            int available1, available2;
            ThreadPool.GetAvailableThreads(out available1, out available2);

            return (max1 - available1);
        }

        static void Main(string[] args)
        {
            ThreadPoolTest();            
                 
            Console.ReadKey();  //按下任意键结束程序       
        }
    }
}

                                           

运行结果如下:

时间                    活动线程数      线程名称        状态
00:00:00.0107238        1                Task1            started
00:00:00.0140175        3                Task3            started
00:00:00.0151379        7                Task7            started
00:00:00.0160629        8                Task2            started
00:00:00.0165277        8                Task8            started
00:00:00.0167671        9                Task5            started
00:00:00.0169506        10              Task9            started
00:00:00.0170967        10              Task4            started
00:00:00.0172783        10              Task10          started
00:00:00.0174646        10              Task6            started
00:00:01.0162788        11              Task11          started
00:00:02.0156464        12              Task12          started
00:00:03.0152283        13              Task13          started
00:00:04.0146323        14              Task14          started
00:00:05.0141607        15              Task15          started
00:00:06.0136234        16              Task16          started
00:00:07.0640600        17              Task17          started
00:00:08.0624471        18              Task18          started
00:00:09.0621401        19              Task19          started
00:00:10.0619472        20              Task20          started
00:00:38.7566261        20              Task1           finished
00:00:38.7576175        20              Task3           finished
00:00:38.7586037        20              Task22          started
00:00:38.7589606        20              Task10          finished
00:00:38.7609881        20              Task23          started
00:00:38.7644790        20              Task4           finished
00:00:38.7653911        20              Task24          started
00:00:38.7661620        20              Task9           finished
00:00:38.7667461        20              Task25          started
00:00:38.7676772        20              Task21          started
00:00:38.7683277        20              Task8           finished
00:00:38.7689285        20              Task26          started
00:00:38.7693858        20              Task2           finished
00:00:38.7700532        20              Task6           finished
00:00:38.7706129        20              Task28          started
00:00:38.7711820        20              Task5           finished
00:00:38.7716580        20              Task29          started
00:00:38.7722943        20              Task27          started
00:00:38.7728069        20              Task7           finished
00:00:38.7733115        20              Task30          started
00:00:39.7583735        20              Task11          finished
00:00:39.7591793        20              Task31          started
00:00:40.7578469        20              Task12          finished
00:00:40.7593474        20              Task32          started
00:00:41.7574471        20              Task13          finished
00:00:41.7582969        20              Task33          started
00:00:42.7569026        20              Task14          finished
00:00:42.7576400        20              Task34          started
00:00:43.7563349        20              Task15          finished
00:00:43.7570931        20              Task35          started
00:00:44.7559455        20              Task16          finished
00:00:44.7567992        20              Task36          started
00:00:45.7593267        20              Task17          finished
00:00:45.7599964        20              Task37          started
00:00:46.7568787        20              Task18          finished
00:00:46.7575400        20              Task38          started
00:00:47.7562341        20              Task19          finished
00:00:47.7569503        20              Task39          started
00:00:48.7568063        20              Task20          finished
00:00:48.7574898        20              Task40          started
00:01:17.4420354        20              Task22          finished
00:01:17.4438299        20              Task41          started
00:01:17.4464655        20              Task23          finished
00:01:17.4478110        20              Task42          started
00:01:17.4488933        20              Task24          finished
00:01:17.4496002        20              Task43          started
00:01:17.4508097        20              Task21          finished
00:01:17.4513800        20              Task44          started
00:01:17.4520468        20              Task25          finished
00:01:17.4526202        20              Task45          started
00:01:17.4532567        20              Task28          finished
00:01:17.4537159        20              Task46          started
00:01:17.4546202        20              Task26          finished
00:01:17.4552586        20              Task47          started
00:01:17.4558928        20              Task27          finished
00:01:17.4564289        20              Task48          started
00:01:17.4571296        20              Task30          finished
00:01:17.4577266        20              Task49          started
00:01:17.4582889        20              Task29          finished
00:01:17.4592571        20              Task50          started
00:01:18.4418865        20              Task31          finished
00:01:19.4424421        19              Task32          finished
00:01:20.4399553        18              Task33          finished
00:01:21.4405072        17              Task34          finished
00:01:22.4400143        16              Task35          finished
00:01:23.4394151        15              Task36          finished
00:01:24.4429568        14              Task37          finished
00:01:25.4404414        13              Task38          finished
00:01:26.4399282        12              Task39          finished
00:01:27.4404093        11              Task40          finished
00:01:56.1459537        10              Task41          finished
00:01:56.1485649        9               Task42          finished
00:01:56.1505286        8               Task43          finished
00:01:56.1514803        7               Task44          finished
00:01:56.1534702        6               Task45          finished
00:01:56.1544100        5               Task46          finished
00:01:56.1552989        4               Task47          finished
00:01:56.1574599        3               Task48          finished
00:01:56.1586138        2               Task49          finished
00:01:56.1602353        1               Task50          finished

(注意,由于线程轮换的不确定性,每次结果都会稍有不同)

从结果可以看出,前十个线程很短时间内开始,从第十一个线程开始则要经过较长一段时间才会创建(大约一秒)。从第二十个线程开始,要等前面的任务完成,新任务才能开始(这里等了一段较长时间),完成一个,就开始一个,线程总数保持不变。直到任务数小于线程上限,活动线程数才开始逐渐减少。

总之,线程的运行过程可以描述如下(为了叙述方便,我们假设下限为10,上限为20):

1.当线程池被创建后,里面就会创建10个空线程(和下限值相同)。

2.当我们向线程池中排入一个任务后,就会有一个空线程接手该任务,然后运行起来。随着我们不断向线程池中排入任务,线程池中的空线程逐一接手并执行任务。

3.随着任务的不断增加,在某一时刻任务数量会超出下限,这时线程的数量就不够用了,但线程池并不会立即创建新线程,而是等待大约500毫秒左右,这么做的目的是看看在这段时间内是否有其他线程完成任务来接手这个请求,这样就可以避免因创建新线程而造成的消耗。如果这段时间内没有线程完成任务,就创建一个新线程去执行新任务。

4.在任务数量超过下限后,随着新任务的不断排入,线程池中线程数量持续增加,直至线程数量达到上限值为止。

5.当线程数量达到上限时,继续增加任务,线程数量将不再增加。比如你向线程池中排入50个任务,则只有20个进入线程池(和上限相同),另外30个在线程池外排队等待。当线程池中的某个线程完成任务后,并不会立即终止,而是从等待队列中选择一个任务继续执行,这样就减少了因创建和销毁线程而消耗的时间。

6.随着任务逐步完成,线程池外部等候的任务被逐步调入线程池,任务的数量逐步减少,但线程的数量保持恒定,始终为20(和上限值相同)。

7.随着任务被逐步完成,总有某一时刻,任务数量会小于上限值,这时线程池内多余的线程会在空闲2分钟后被释放并回收相关资源。线程数目逐步减少,直到达到下限值为止。

8.当任务数量减小到下限值之下时,线程池中的线程数目保持不变(始终和下限值相同),其中一部分在执行任务,另一部分处于空运行状态。

9.当所有任务都完成后,线程池恢复初始状态,运行10个空线程。

由上面的论述可以看出线程池提高效率的关键是一个线程完成任务后可以继续为其他任务服务,这样就可以使用有限的几个固定线程轮流为大量的任务服务,从而减少了因频繁创建和销毁线程所造成的消耗。

下面是修改Sleep()时间后再次运行的结果。

时间                    活动线程数      线程名称        状态
00:00:00.0189359        9                Task2           started
00:00:00.0201952        9                Task1           started
00:00:00.0208337        9                Task9           started
00:00:00.0212512        9                Task6           started
00:00:00.0217229        9                Task8           started
00:00:00.0223773        9                Task7           started
00:00:00.0227899        9                Task4           started
00:00:00.0231066        9                Task3           started
00:00:00.0235849        9                Task5           started
00:00:01.0163201        10              Task10          started
00:00:02.0157285        11              Task11          started
00:00:03.0153552        12              Task12          started
00:00:04.0147554        13              Task13          started
00:00:05.0142889        14              Task14          started
00:00:06.0208071        15              Task15          started
00:00:06.7049884        15              Task2           finished
00:00:06.7070401        15              Task16          started
00:00:06.7074667        15              Task7           finished
00:00:06.7078560        15              Task17          started
00:00:06.7082879        15              Task3           finished
00:00:06.7086411        15              Task18          started
00:00:06.7092260        15              Task5           finished
00:00:06.7096711        15              Task19          started
00:00:06.7101447        15              Task6           finished
00:00:06.7111514        15              Task20          started
00:00:06.7146020        15              Task8           finished
00:00:06.7154948        15              Task21          started
00:00:06.7176304        15              Task9           finished
00:00:06.7193209        15              Task22          started
00:00:06.7201892        15              Task1           finished
00:00:06.7208777        15              Task23          started
00:00:06.7216695        15              Task4           finished
00:00:06.7230875        15              Task24          started
00:00:07.5200857        16              Task25          started
00:00:07.7023973        16              Task10          finished
00:00:07.7036477        16              Task26          started
00:00:08.5195702        17              Task27          started
00:00:08.7011903        17              Task11          finished
00:00:08.7025396        17              Task28          started
00:00:09.5187647        18              Task29          started
00:00:09.7008700        18              Task12          finished
00:00:09.7019751        18              Task30          started
00:00:10.5246393        19              Task31          started
00:00:10.7015599        19              Task13          finished
00:00:10.7025033        19              Task32          started
00:00:11.5184213        20              Task33          started
00:00:11.7000063        20              Task14          finished
00:00:11.7006650        20              Task34          started
00:00:12.6995112        20              Task15          finished
00:00:12.7003309        20              Task35          started
00:00:13.3848916        20              Task16          finished
00:00:13.3854166        20              Task36          started
00:00:13.3861911        20              Task17          finished
00:00:13.3865749        20              Task37          started
00:00:13.3875311        20              Task18          finished
00:00:13.3881098        20              Task38          started
00:00:13.3887310        20              Task19          finished
00:00:13.3893513        20              Task39          started
00:00:13.3920574        20              Task20          finished
00:00:13.3925907        20              Task40          started
00:00:13.3949921        20              Task21          finished
00:00:13.3956187        20              Task41          started
00:00:13.3980055        20              Task22          finished
00:00:13.3985151        20              Task42          started
00:00:13.3998460        20              Task23          finished
00:00:13.4002990        20              Task43          started
00:00:13.4022154        20              Task24          finished
00:00:13.4027421        20              Task44          started
00:00:14.1998829        20              Task25          finished
00:00:14.2003381        20              Task45          started
00:00:14.3827441        20              Task26          finished
00:00:14.3833120        20              Task46          started
00:00:15.1987473        20              Task27          finished
00:00:15.1993380        20              Task47          started
00:00:15.3824547        20              Task28          finished
00:00:15.3830691        20              Task48          started
00:00:16.1973072        20              Task29          finished
00:00:16.1980986        20              Task49          started
00:00:16.3807865        20              Task30          finished
00:00:16.3814246        20              Task50          started
00:00:17.2490713        20              Task31          finished
00:00:17.4271196        19              Task32          finished
00:00:18.2423627        18              Task33          finished
00:00:18.4271299        17              Task34          finished
00:00:19.4241792        16              Task35          finished
00:00:20.1084177        15              Task36          finished
00:00:20.1103091        14              Task37          finished
00:00:20.1113160        13              Task38          finished
00:00:20.1123464        12              Task39          finished
00:00:20.1162134        11              Task40          finished
00:00:20.1190785        10              Task41          finished
00:00:20.1220864        9               Task42          finished
00:00:20.1229967        8               Task43          finished
00:00:20.1259507        7               Task44          finished
00:00:20.9331819        6               Task45          finished
00:00:21.1069320        5               Task46          finished
00:00:21.9229240        4               Task47          finished
00:00:22.1070568        3               Task48          finished
00:00:22.9214465        2               Task49          finished
00:00:23.1049741        1               Task50          finished

抛砖引玉,还有什么更好的方法,还请高手指教。