首页 > 代码库 > c#自己实现线程池功能(一)

c#自己实现线程池功能(一)

线程池的技术背景

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源,所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。

线程池技术如何提高服务器程序的性能

我所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:

假设在一台服务器完成一项任务的时间为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而在处理请求时浪费时间,从而提高效率。

这些都是假设,不能充分说明问题,下面我将讨论线程池的简单实现并对该程序进行对比测试,以说明线程技术优点及应用领域。

线程池的简单实现及对比测试

一般一个简单线程池至少包含下列组成部分。

  1. 线程池管理器(ThreadPoolManager):用于创建并管理线程池
  2. 工作线程(WorkThread): 线程池中线程
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
  4. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。

接下来我演示了一个 最简单的线程池。没有进行任何优化的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;

namespace ThreadManager
{
    public class ThreadPoolManager
    {
        private int MaxThreadNum;
        private int MinThreadNum;
        private int GrowStepNum;
        //线程数量
        public int ThreadNum{get;set;}
        //默认线程数量
        public int DefaultThreadNum { get; set; }

        private Queue<Task> TaskQueue;
        private Queue<WorkThread> WorkThreadList;

        public ThreadPoolManager(int i)
        {
            TaskQueue = new Queue<Task>();
            WorkThreadList = new Queue<WorkThread>();
            DefaultThreadNum = 10;
            if (i > 0)
                DefaultThreadNum = i;
            CreateThreadPool(i);
        }
        public ThreadPoolManager():this(10)
        {
        }
        public bool IsAllTaskFinish()
        {
            return TaskQueue.Count == 0;
        }
        public void CreateThreadPool(int i)
        {
            if (WorkThreadList == null)
                WorkThreadList = new Queue<WorkThread>();
            lock (WorkThreadList)
            {
                for (int j = 0; j < i;j++)
                {
                    ThreadNum++;
                    WorkThread workthread = new WorkThread(ref TaskQueue,ThreadNum);
                    WorkThreadList.Enqueue(workthread);
                }
            }
        }
        public void AddTask(Task task)
        {
           
            if (task == null)
                return;
            lock (TaskQueue)
            {
                TaskQueue.Enqueue(task);
            }
            //Monitor.Enter(TaskQueue);
            //TaskQueue.Enqueue(task);
            //Monitor.Exit(TaskQueue);
        }
        public void CloseThread()
        {
            //Object obj = null;
            while (WorkThreadList.Count != 0)
            {
                try
                {
                    WorkThread workthread = WorkThreadList.Dequeue();
                    workthread.CloseThread();
                    continue;
                }
                catch (Exception)
                {
                }
                break;
            }
        }
    }
}
工作线程类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadManager
{
    public class WorkThread
    {
        public int ThreadNum { get; set; }
        private bool flag;
        private Queue<Task> TaskQueue;
        private Task task;
        public WorkThread(ref Queue<Task> queue, int i)
        {
            this.TaskQueue = queue;
            ThreadNum = i;
            flag = true;
            new Thread(run).Start();
        }
        public void run()
        {
            while (flag && TaskQueue != null)
            {
                //获取任务
                lock (TaskQueue)
                {
                    try
                    {
                            task = TaskQueue.Dequeue();
                    }
                    catch (Exception)
                    {
                        task = null;
                    }
                    if (task == null)
                        continue;
                }
                try
                {
                    task.SetEnd(false);
                    task.StartTask();
                }
                catch (Exception)
                {
                }
                try
                {
                    if (!task.IsEnd())
                    {
                        task.SetEnd(false);
                        task.EndTask();
                    }
                }
                catch (Exception)
                {
                }

            }//end of while
        }
        public void CloseThread()
        {
            flag = false;
            try
            {
                if (task != null)
                    task.EndTask();
            }
            catch (Exception)
            {   
            }
        }
    }
}
task类和实现类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ThreadManager
{
    public interface Task
    {
        /// <summary>
        /// set flag of task.
        /// </summary>
        void SetEnd(bool flag);
        /// <summary>
        /// start task.
        /// </summary>
        void StartTask();
        /// <summary>
        /// end task.
        /// </summary>
        void EndTask();
        /// <summary>
        /// get status of task.
        /// </summary>
        /// <returns></returns>
        bool IsEnd();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadManager
{
    public class TestTask:Task
    {
        private bool is_end;
        public void SetEnd(bool flag)
        {
            is_end = flag;
        }
        public void StartTask()
        {
            Run();
        }
        public void EndTask()
        {
            is_end = true;
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":"+"结束!");
        }
        public bool IsEnd()
        {
            return is_end;
        }
        public void Run()
        {
            for (int i = 0; i < 1000; i++)
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":"+i);
            }
        }

    }
}


这个简单的模型存在的问题是,很多时候获取TASK都是在不断的尝试,使得性能降的很低,需要改进的方法是增加一个 信号量的机制,不让程序空转!

在下一篇文章中我会进行优化,使得线程池真正的提高效率!


c#自己实现线程池功能(一)