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都是在不断的尝试,使得性能降的很低,需要改进的方法是增加一个 信号量的机制,不让程序空转!

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

时间: 2024-08-24 22:25:12

c#自己实现线程池功能(一)的相关文章

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

介绍 在上一篇c#自己实现线程池功能(一)中,我们基本实现了一个可以运行的程序,而不能真正的称作线程池.由于是上篇中的代码有个致命的bug那就是没有任务是并不是等待,而是疯狂的进行while循环,并试图lock任务链表,这样带来的问题的就是性能相当低下,程序反映速度很慢(当加入一个新任务后,要过很久这个job才开始运行)造成的原因就是刚才所说的. 为了解决这个问题我们就需要使用某种方法使得程序能够让进程同步. 方法一 使用信号量 我们为了减少对task任务的加锁操作,只有当task不为空时才进行

记5.28大促压测的性能优化&mdash;线程池相关问题

目录: 1.环境介绍 2.症状 3.诊断 4.结论 5.解决 6.对比java实现 废话就不多说了,本文分享下博主在5.28大促压测期间解决的一个性能问题,觉得这个还是比较有意思的,值得总结拿出来分享下. 博主所服务的部门是作为公共业务平台,公共业务平台支持上层所有业务系统(2C.UGC.直播等).平台中核心之一的就是订单域相关服务,下单服务.查单服务.支付回调服务,当然结算页暂时还是我们负责,结算页负责承上启下进行下单.结算.跳支付中心.每次业务方进行大促期间平台都要进行一次常规压测,做到心里

记5.28大促压测的性能优化—线程池相关问题

目录: 1.环境介绍 2.症状 3.诊断 4.结论 5.解决 6.对比java实现 废话就不多说了,本文分享下博主在5.28大促压测期间解决的一个性能问题,觉得这个还是比较有意思的,值得总结拿出来分享下. 博主所服务的部门是作为公共业务平台,公共业务平台支持上层所有业务系统(2C.UGC.直播等).平台中核心之一的就是订单域相关服务,下单服务.查单服务.支付回调服务,当然结算页暂时还是我们负责,结算页负责承上启下进行下单.结算.跳支付中心.每次业务方进行大促期间平台都要进行一次常规压测,做到心里

Android 四种常见的线程池

引入线程池的好处 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 我们来看一下线程池的简单的构造 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecution

几种线程池的实现算法分析

1. 前言 在阅读研究线程池的源码之前,一直感觉线程池是一个框架中最高深的技术.研究后才发现,线程池的实现是如此精巧.本文从技术角度分析了线程池的本质原理和组成,同时分析了JDK.Jetty6.Jetty8.Tomcat的源码实现,对于想了解线程池本质.更好的使用线程池或者定制实现自己的线程池的业务场景具有一定指导意义. 2. 使用线程池的意义 复用:类似WEB服务器等系统,长期来看内部需要使用大量的线程处理请求,而单次请求响应时间通常比较短,此时Java基于操作系统的本地调用方式大量的创建和销

java线程池分析和应用

比较 在前面的一些文章里,我们已经讨论了手工创建和管理线程.在实际应用中我们有的时候也会经常听到线程池这个概念.在这里,我们可以先针对手工创建管理线程和通过线程池来管理做一个比较.通常,我们如果手工创建线程,需要定义线程执行对象,它实现的接口.然后再创建一个线程对象,将我们定义好的对象执行部分装载到线程中.对于线程的创建.结束和结果的获取都需要我们来考虑.如果我们需要用到很多的线程时,对线程的管理就会变得比较困难.我们手工定义线程的方式在时间和空间效率方面会存在着一些不足.比如说我们定义好的线程

Android性能优化之使用线程池处理异步任务

说到线程,我想大家都不陌生,因为在开发时候或多或少都会用到线程,而通常创建线程有两种方式: 1.继承Thread类 2.实现Runnable接口 虽说这两种方式都可以创建出一个线程,不过它们之间还是有一点区别的,主要区别在于在多线程访问同一资源的情况下,用Runnable接口创建的线程可以处理同一资源,而用Thread类创建的线程则各自独立处理,各自拥有自己的资源. 所以,在Java中大多数多线程程序都是通过实现Runnable来完成的,而对于Android来说也不例外,当涉及到需要开启线程去完

Android 性能优化之使用线程池处理异步任务

说到线程,我想大家都不陌生,因为在开发时候或多或少都会用到线程,而通常创建线程有两种方式: 1.继承Thread类 2.实现Runnable接口 虽说这两种方式都可以创建出一个线程,不过它们之间还是有一点区别的,主要区别在于在多线程访问同一资源的情况下,用Runnable接口创建的线程可以处理同一资源,而用Thread类创建的线程则各自独立处理,各自拥有自己的资源. 所以,在Java中大多数多线程程序都是通过实现Runnable来完成的,而对于Android来说也不例外,当涉及到需要开启线程去完

几种线程池的实现算法分析【转载】

原文地址 本文内容 前言 线程池意义 线程池技术要点 小节 参考源码 但凡是一个框架,基本都会涉及线程池问题.虽然你可能没有直接使用,那是因为框架帮你完成了这部分工作. 说,为什么需要线程池呢?试想,现在但凡是写一个服务程序,如果不采用并发或并行的方式,都有点对不起4核.8核,甚至更多的CPU内核,但是如果每次需要线程,都创建一次,这对性能的消耗,比较大,更加合适的做法是,在程序初始化时,一次性把所有线程都创建好,这样,当需要的时候,直接拿来过用~ 前言 在阅读研究线程池的源码之前,一直感觉线程