线程池的技术背景

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

线程池技术怎样提高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都是在不断的尝试,使得性能降的非常低,须要改进的方法是添加一个 信号量的机制。不让程序空转!

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


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

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

    介绍 在上一篇c#自己实现线程池功能(一)中,我们基本实现了一个能够执行的程序.而不能真正的称作线程池.因为是上篇中的代码有个致命的bug那就是没有任务是并非等待,而是疯狂的进行while循环,并试图 ...

  2. C语言实现线程池功能

    1. 线程池基本原理 2. 线程池C语言实现 2.1 线程池的数据结构 #include <stdio.h> #include <pthread.h> #include < ...

  3. java线程池分析和应用

    比较 在前面的一些文章里,我们已经讨论了手工创建和管理线程.在实际应用中我们有的时候也会经常听到线程池这个概念.在这里,我们可以先针对手工创建管理线程和通过线程池来管理做一个比较.通常,我们如果手工创 ...

  4. ExecutorService 建立一个多线程的线程池的步骤

    ExecutorService 建立一个多线程的线程池的步骤: 线程池的作用: 线程池功能是限制在系统中运行的线程数. 依据系统的环境情况,能够自己主动或手动设置线程数量.达到执行的最佳效果:少了浪费 ...

  5. Android 四种常见的线程池

    引入线程池的好处 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 我们来看一下线程池的简单的构造 public ThreadPoolExec ...

  6. Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求

    Elasticsearch源码分析—线程池(十一) 转自:https://www.felayman.com/articles/2017/11/10/1510291570687.html 线程池 每个节 ...

  7. 基于队列queue实现的线程池

    本文通过文章同步功能推送至博客园,显示排版可能会有所错误,请见谅! 写在前文:在Python中给多进程提供了进程池类,对于线程,Python2并没有直接提供线程池类(Python3中提供了线程池功能) ...

  8. 原生线程池这么强大,Tomcat 为何还需扩展线程池?

    前言 Tomcat/Jetty 是目前比较流行的 Web 容器,两者接受请求之后都会转交给线程池处理,这样可以有效提高处理的能力与并发度.JDK 提高完整线程池实现,但是 Tomcat/Jetty 都 ...

  9. JDK线程池框架Executor源码阅读

    Executor框架 Executor ExecutorService AbstractExecutorService ThreadPoolExecutor ThreadPoolExecutor继承A ...

随机推荐

  1. linux公社的大了免费在线android资料

    2011年linux数据库的android在线分享 linux公社:开源公社             本文撰写:杨凯专属频道 2011年9月12日 21:39 <目录> Android 3 ...

  2. javacsript (十一) 对象

    他的对象的概念和python的字典的格式一样, JavaScript 对象 对象由花括号分隔.在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义.属性由逗号分隔: var ...

  3. Ubuntu通过源代码编译安装Octave 4.0

    本教程/笔记,意在指导在Ubuntu及其它Linux系统上怎样通过源代码安装Octave. Octave简单介绍 Octave是GNU旗下取代matlab的数学工具软件,语法与matlab高度兼容.而 ...

  4. Swift - 自定义UIActivity分享

    UIActivity可以十分方便地将文字.图片等内容进行分享,比如分享到微信.微博.发送邮件.短信等等.我们不仅可以分享内容出来,也可以在自己的App里添加自己的分享按钮或隐藏已有的分享按钮来实现定制 ...

  5. Win7和VS2013上使用Intel的TBB

    源地址:http://www.th7.cn/system/win/201505/103966.shtml http://wenku.baidu.com/link?url=zH7vwmWltWF5R-9 ...

  6. Ajax请求URL后加随机数原理

    原文:Ajax请求URL后加随机数原理 例如: $.ajax({             type: "GET",    url: "login.action?ran=& ...

  7. [ACM] hdu 4405 Aeroplane chess (概率DP)

    Aeroplane chess Problem Description Hzz loves aeroplane chess very much. The chess map contains N+1 ...

  8. codeforces 598B Queries on a String

    题目链接:http://codeforces.com/problemset/problem/598/B 题目分类:字符串 题意:给定一个串,然后n次旋转,每次给l,r,k,表示区间l到r的字符进行k次 ...

  9. 贪心算法-找零钱(C#实现)

    找零钱这个问题很清楚,无非就是始终拿可以取的最大面值来找,最后就使得张数最小了,这个实现是在假设各种面值足够多的情况下. 首先拖出一个界面来,最下面是一个listbox控件 对应的代码:问题比较简单, ...

  10. 使用FragmentTabhost取代Tabhost

       如今Fragment使用越来越广了,尽管Fragment寄生在Activity下.可是它的出现对于开发人员来说是一件很幸运的事,使开发的效率更高效了.好了以下就说说 FragmentTabhos ...