zoukankan      html  css  js  c++  java
  • c#为了实现自己的线程池功能(一)

    线程池的技术背景

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

    线程池技术怎样提高server程序的性能

    我所提到server程序是指可以接受客户请求并能处理请求的程序。而不仅仅是指那些接受网络客户请求的网络server程序。

    多线程技术主要解决处理器单元内多个线程运行的问题,它能够显著降低处理器单元的闲置时间,添加处理器单元的吞吐能力。

    但假设对多线程应用不当,会添加对单个任务的处理时间。能够举一个简单的样例:

    如果在一台server完毕一项任务的时间为T

         T1 创建线程的时间
          T2 在线程中运行任务的时间。包含线程间同步所需时间
          T3 线程销毁的时间

    显然T = T1+T2+T3。注意这是一个极度简化的如果。

    能够看出T1,T3是多线程本身的带来的开销。我们渴望降低T1,T3所用的时间。从而降低T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。

    显然这是突出了线程的弱点(T1,T3),而不是长处(并发性)。

    线程池技术正是关注怎样缩短或调整T1,T3时间的技术,从而提高server程序性能的。它把T1,T3分别安排在server程序的启动和结束的时间段或者一些空暇的时间段,这样在server程序处理客户请求时,不会有T1。T3的开销了。

    线程池不仅调整T1,T3产生的时间段,并且它还显著降低了创建线程的数目。在看一个样例:

    如果一个server一天要处理50000个请求,而且每一个请求须要一个单独的线程完毕。我们比較利用线程池技术和不利于线程池技术的server处理这些请求时所产生的线程总数。在线程池中,线程数通常是固定的。所以产生线程总数不会超过线程池中线程的数目或者上限(下面简称线程池尺寸)。而如果server不利用线程池来处理这些请求则线程总数为50000。一般线程池尺寸是远小于50000。所以利用线程池的server程序不会为了创建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都是在不断的尝试,使得性能降的非常低,须要改进的方法是添加一个 信号量的机制。不让程序空转!



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


  • 相关阅读:
    $Noip2011/Luogu1311$ 选择客栈
    $Noip2013/Luogu1970$ 花匠 $dp$+思维
    $CF1063B Labyrinth$ $01$最短路/$01BFS$
    $UVA10559 Blocks $区间$dp$
    $SCOI2009 windy$数 数位$dp$
    $cometoj#4 D $求和 不是$dp$
    Manacher算法总结
    题解 P1537 【弹珠】
    题解 P4609 【[FJOI2016]建筑师】
    字符串专题随笔
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5046445.html
Copyright © 2011-2022 走看看