Net线程池设计

功能描述:

  1. 支持创建多个线程池,并统一管理
  2. 支持不同线程池的容量控制,以及最少活动线程的设置
  3. 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收

结构设计:

  • ThreadWorkerPoolManager: 线程池管理器,用于统一创建,获取,销毁线程池,使用单例模式
  • ThreadWorkerPool: 线程池,用于管理指定数量的线程,由ThreadWorkerPoolManager管理,自身无法创建与销毁
  • TheadWorkerPoolItem: 线程池项,用于包装线程工作器,协助ThreadWorkerPool更好的管理线程,例如取出,放回,闲时的控制
  • TheadWorker: 线程工作器,用于包装系统线程System.Threading.Thread,使其可以重复使用,减少Thrad创建和销毁的性能开销

  结构关系图:

  

 详细设计:

  ThreadWoker

  要点设计:

  1. 完成一次任务后,System.Threading.Thread不能被系统销毁, 默认情况下new Thread(ThreadStart start).Start(), 当ThreadStart委托的任务完成后,系统将销毁该线程,也就是说创建一个System.Threading.Thread实例只能使用一次;为了使线程能被重复使用,ThreadWoker将使用 while+sleeping 的方式对系统线程进行包装,同时使用AutoResetEvent代替Thread.Sleep(timeout)来达到更佳的控制
  2. 闲时设计,线程资源是极其宝贵的系统资源,如果线程池中存在大量的空闲线程这是一种浪费,极端情况下将影响系统的稳定性和工作效率;ThreadWorker将使用AutoResetEvent和事件通知的方式来代替在线程池中定期轮询检查的方式,每完成一个任务将重新开始空闲时间的计算,如果ThreadWorker在线程池中被取出,那么ThreadWorker空闲时间将永远不会到期,直到ThreadWorker被返回线程池后才重新开始空闲时间的计算

  状态图:

  

  关键代码:

  

  1. 1 private void ThreadWorking()
  2. 2 {
  3. 3 while (_status != ThreadWorkerStatus.Abort)
  4. 4 {
  5. 5 //WaitOne 返回false表示等待超时,true接到取消等待的通知
  6. 6 //这里利用AutoResetEvent.WaitOne的特性来设计闲时控制,false表示空闲到期,true表示新的任务开始
  7. 7 if (!_waitEvent.WaitOne(_idleTime))
  8. 8 {
  9. 9 if (!_isCanIdleExpired) //_isCanIdleExpired变量控制是否允许超时,例如被取出后将不能超时
  10. 10 continue;
  11. 11
  12. 12 _status = ThreadWorkerStatus.Abort;
  13. 13 _waitEvent.Close();
  14. 14 _waitEvent.Dispose();
  15. 15 if (OnIdleExpired != null)
  16. 16 OnIdleExpired(this, null); //空闲到期事件通知
  17. 17 return;
  18. 18 }
  19. 19 else if (_status == ThreadWorkerStatus.Abort)
  20. 20 return;
  21. 21
  22. 22 try
  23. 23 {
  24. 24 Working();
  25. 25 }
  26. 26 catch (Exception ex)
  27. 27 {
  28. 28 _logger.TraceEvent(TraceEventType.Error, (int)TraceEventType.Error, ex.ToString());
  29. 29 }
  30. 30 finally
  31. 31 {
  32. 32 _status = ThreadWorkerStatus.Idle;
  33. 33 if (OnWorkCompleted != null)
  34. 34 OnWorkCompleted(this, null); //任务完成事件通知
  35. 35 }
  36. 36 }
  37. 37 }
  1. 1      public void Work()
  2. 2 {
  3. 3 if (_status == ThreadWorkerStatus.Abort)
  4. 4 throw new InvalidOperationException("this ThreadWorker was Abort!");
  5. 5
  6. 6 if (_status == ThreadWorkerStatus.Working)
  7. 7 throw new InvalidOperationException("this ThreadWorker was working, unable to duplicate work!");
  8. 8
  9. 9 _status = ThreadWorkerStatus.Working;
  10. 10 _waitEvent.Set(); //通知线程有个新的工作要开始
  11. 11 }

  ThreadWorkerPoolItem

  要点设计:

  1. 链接ThreadWorker和线程池,线程池通过ThreadWorkerPoolItem控制ThreadWorker在线程池的取出,放回,销毁
  2. 通过订阅ThreadWorker的空闲到期事件OnIdleExpired,来完成线程池对线程的移除
  3. 通过订阅ThreadWorker的任务完成事件OnWorkCompleted,来完成线程返回线程池的操作
  4. 提供剩余空闲时间查询,来为线程池提供更优线程取出方案

  完整代码:

  1. 1 public sealed class ThreadWorkerPoolItem
  2. 2 {
  3. 3 private ThreadWorkerPoolItemStatus _status;
  4. 4 private readonly ThreadWorkerBase _threadWorker;
  5. 5 private readonly ThreadWorkerPoolBase _threadWorkerPool;
  6. 6 private readonly int _idleTime;
  7. 7 private DateTime _startIdleTime;
  8. 8
  9. 9 internal ThreadWorkerPoolItem(ThreadWorkerPoolBase pool, ThreadWorkerBase threadWorker, ThreadWorkerPoolSettings poolSettings)
  10. 10 {
  11. 11 _threadWorkerPool = pool;
  12. 12 _threadWorker = threadWorker;
  13. 13 _threadWorker.OnIdleExpired += _threadWorker_OnIdleExpired;
  14. 14 _threadWorker.OnWorkCompleted += _threadWorker_OnWorkCompleted;
  15. 15 _threadWorker.Start();
  16. 16 _status = ThreadWorkerPoolItemStatus.Idle;
  17. 17 _idleTime = poolSettings.IdleTime;
  18. 18 }
  19. 19
  20. 20 void _threadWorker_OnWorkCompleted(object sender, EventArgs args)
  21. 21 {
  22. 22 _threadWorkerPool.Return(this);
  23. 23 }
  24. 24
  25. 25 void _threadWorker_OnIdleExpired(object sender, EventArgs args)
  26. 26 {
  27. 27 _threadWorkerPool.Remove(this);
  28. 28 }
  29. 29
  30. 30 internal ThreadWorkerPoolItemStatus Status
  31. 31 {
  32. 32 get
  33. 33 {
  34. 34 if (_threadWorker.Status == ThreadWorkerStatus.Abort || _status == ThreadWorkerPoolItemStatus.Abort)
  35. 35 return ThreadWorkerPoolItemStatus.Abort;
  36. 36
  37. 37 return _status;
  38. 38 }
  39. 39 }
  40. 40
  41. 41 internal int SurplusIdleTime
  42. 42 {
  43. 43 get
  44. 44 {
  45. 45 if (_status == ThreadWorkerPoolItemStatus.Take || _idleTime == -1)
  46. 46 return -1;
  47. 47
  48. 48 int idledTime = (int)(_startIdleTime - DateTime.Now).TotalMilliseconds;
  49. 49 if (idledTime >= _idleTime)
  50. 50 return 0;
  51. 51
  52. 52 return idledTime;
  53. 53 }
  54. 54 }
  55. 55
  56. 56 internal void SetTake()
  57. 57 {
  58. 58 _threadWorker.IsCanIdleExpried = false;
  59. 59 _status = ThreadWorkerPoolItemStatus.Take;
  60. 60 }
  61. 61
  62. 62 internal void SetIdle()
  63. 63 {
  64. 64 _startIdleTime = DateTime.Now;
  65. 65 _status = ThreadWorkerPoolItemStatus.Idle;
  66. 66 _threadWorker.IsCanIdleExpried = true;
  67. 67 }
  68. 68
  69. 69 internal ThreadWorkerBase ThreadWorker
  70. 70 {
  71. 71 get { return _threadWorker; }
  72. 72 }
  73. 73 }

  ThreadWorkerPool

  要点设计:

  1. 使用Lock配合ThreadWorkerPoolItem的状态来确保多线程下,每次取出的都是空闲的ThreadWorker
  2. 取出的超时设计,由于线程池有容量控制,高并发下必然导致线程池满负荷,提供超时设置,有利于使用者自行控制满负荷情况下的处理;ThreadWorkerPool将使用while+sleeping的方式,同时使用AutoResetEvent代替Thread.Sleep(timeout)来达到更佳的控制,当一个线程被放回线程池时,另一等待获取者立即获取,而无需等待下一次轮询的到来

  关键代码:

  1. 1 protected bool TryTake(int timeout, out ThreadWorkerBase threadWorker)
  2. 2 {
  3. 3 threadWorker = null;
  4. 4 lock (_takeLocker)
  5. 5 {
  6. 6 ThreadWorkerPoolItem worker = null;
  7. 7 DateTime startWaitTime;
  8. 8 while (!_isDestoryed)
  9. 9 {
  10. 10 worker = _threadWorkerList.Where(e => e.Status == Core.ThreadWorkerPoolItemStatus.Idle).OrderByDescending(e => e.SurplusIdleTime).FirstOrDefault();
  11. 11 if (worker == null)
  12. 12 {
  13. 13 if (_threadWorkerList.Count < _settings.MaxThreadWorkerCount)
  14. 14 {
  15. 15 worker = this.CreatePoolItem(_threadWorkerList.Count + 1, _settings.IdleTime);
  16. 16 worker.SetTake();
  17. 17 _threadWorkerList.Add(worker);
  18. 18 threadWorker = worker.ThreadWorker;
  19. 19 return true;
  20. 20 }
  21. 21
  22. 22 startWaitTime = DateTime.Now;
  23. 23 if (!_takeWaitEvent.WaitOne(timeout))
  24. 24 {
  25. 25 threadWorker = null;
  26. 26 return false;
  27. 27 }
  28. 28
  29. 29 if (timeout != -1)
  30. 30 {
  31. 31 timeout = timeout - (int)(DateTime.Now - startWaitTime).TotalMilliseconds;
  32. 32 if (timeout <= 0)
  33. 33 {
  34. 34 threadWorker = null;
  35. 35 return false;
  36. 36 }
  37. 37 }
  38. 38 continue;
  39. 39 }
  40. 40
  41. 41 threadWorker = worker.ThreadWorker;
  42. 42 worker.SetTake();
  43. 43 return true;
  44. 44 }
  45. 45
  46. 46 threadWorker = null;
  47. 47 return false;
  48. 48 }
  49. 49 }
  1. 1 internal void Return(ThreadWorkerPoolItem item)
  2. 2 {
  3. 3 item.SetIdle();
  4. 4 _takeWaitEvent.Set();
  5. 5 }

  ThreadWorkerPoolManager使用单例模式管理,代码过于简单这里就不贴了......

  有兴趣的同学可以点击这里进行下载源码查看:Nutshell.ThreadWorkerPool.zip

  github 开源地址: https://github.com/zcylife/Nutshell

Net线程池设计的更多相关文章

  1. 【转载】深度解读 java 线程池设计思想及源码实现

    总览 开篇来一些废话.下图是 java 线程池几个相关类的继承结构: 先简单说说这个继承结构,Executor 位于最顶层,也是最简单的,就一个 execute(Runnable runnable) ...

  2. Java并发指南12:深度解读 java 线程池设计思想及源码实现

    ​深度解读 java 线程池设计思想及源码实现 转自 https://javadoop.com/2017/09/05/java-thread-pool/hmsr=toutiao.io&utm_ ...

  3. Nutshell.ThreadWorkerPool .Net线程池设计

    功能描述: 支持创建多个线程池,并统一管理 支持不同线程池的容量控制,以及最少活动线程的设置 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收 结构设计: ThreadWorker ...

  4. Java - 线程池设计与选择

    http://ifeve.com/how-to-calculate-threadpool-size/ 任务一般可分为:CPU密集型.IO密集型.混合型,对于不同类型的任务需要分配不同大小的线程池. C ...

  5. 谈谈Java的线程池设计

    在实际项目中,如果因为想异步执行暂时性的任务而不断创建线程是很浪费资源的事情(当一个任务执行完后,线程也没用了).这种情况下,最好是将任务提交给线程池执行. 所谓池,就是将管理某一种资源,对资源进行复 ...

  6. 分享一个自制的 .net线程池

    扯淡 由于项目需求,需要开发一些程序去爬取一些网站的信息,算是小爬虫程序吧.爬网页这东西是要经过网络传输,如果程序运行起来串行执行请求爬取,会很慢,我想没人会这样做.为了提高爬取效率,必须使用多线程并 ...

  7. 线程池原理及创建(C++实现)

    http://www.cnblogs.com/lidabo/p/3328402.html 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关.另外 ...

  8. 线程池原理及创建并C++实现

    本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关.另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整线程池中线程的数量.文章的最后,我们 ...

  9. C#的线程池的那些事

    最近在做站时发现,线程池的问题很棘手,所以总结了一篇关于线程池的文章,原文地址:http://www.shuonar.com/blog/ac16496b-87ec-4790-a9ea-d69bbffa ...

随机推荐

  1. PYTHON 正则表达示入门

    确实是实践出真知,自己手打代码之后,以前停在理论上的东东,慢慢可以进入实战了. 比如,MATCH和SEARCH之间的区别. #encoding: UTF-8 import re pattern = r ...

  2. .Net框架与框架类库-转

    http://blog.csdn.net/rrrfff/article/details/6686493 .NET Framework 具有两个主要组件:公共语言运行库和 .NET Framework类 ...

  3. 创建.NET应用程序所经历的步骤

    1.使用某种.NET兼容语言(如C#)编写应用程序.2.把代码编译为(CIL),存储在程序集中.3.在执行代码时(如果这是一个可执行文件,就自动运行,或者在其他代码使用它时运行),首先必须使用JIT( ...

  4. Android 实现ActionBar定制

    我们在使用Android手机时,经常发现应用中的ActionBar和我们平时使用的ActionBar相差非常大.简单的说就是,其他应用的 ActionBar为什么那么绚丽,自己应用的ActionBar ...

  5. 【HDOJ】3184 All Can Do

    简单数学题. #include <cstdio> #include <cstring> #include <cstdlib> int main() { int t; ...

  6. hackerrank【Lego Blocks】:计数类dp

    题目大意: 修一个层数为n,长度为m的墙,每一层可以由长度为1.2.3.4的砖块构成. 每一层都在同一个长度处出现缝隙是方案非法的,问合法的方案数有多少种 思路: 先求出总方案,再减去所有非法的方案数 ...

  7. hadoop2.2.0 MapReduce分区

    package com.my.hadoop.mapreduce.partition; import java.util.HashMap;import java.util.Map; import org ...

  8. scroll pagination.js数据重复加载、分页问题

    scroll pagination.js数据重复加载.分页问题 解决办法 参考资料: http://blog.csdn.net/dyw442500150/article/details/1753242 ...

  9. mnist数据集转换bmp图片

    Mat格式mnist数据集下载地址:http://www.cs.nyu.edu/~roweis/data.html Matlab转换代码: load('mnist_all.mat'); type = ...

  10. wxWidgets刚開始学习的人导引(3)——wxWidgets应用程序初体验

    wxWidgets刚開始学习的人导引全文件夹   PDF版及附件下载 1 前言2 下载.安装wxWidgets3 wxWidgets应用程序初体验4 wxWidgets学习资料及利用方法指导5 用wx ...