C#线程篇---线程池如何管理线程(6完结篇)
C#线程基础在前几篇博文中都介绍了,现在最后来挖掘一下线程池的管理机制,也算为这个线程基础做个完结。
我们现在都知道了,线程池线程分为工作者线程和I/O线程,他们是怎么管理的?
对于Microsoft设计的CLR线程池,线程池会随着CLR的每个版本的发布,都会发生变化,很难去挖掘,这里的提议是:
最好将线程看成一个黑盒。不要拿单个应用程序去衡量这个黑盒的性能,因为它对任何一个应用程序来说都无法做到完美。
相反,它是一种常规用途的线程调度技术,面向大量应用程序;它对某些应用程序的效果要好于其他应用程序。
目前,它的工作情况非常理想,这里建议你信任它,因为你很难高出一个比CLR自带的那个更好的线程池。另外,随着时间的推移,线程池代码内部,会更改它管理线程的方式,所以大多数应用程序的性能会变得越来越好。
CLR允许开发人员设置线程池创建最大线程数。然后有些开发人员感觉好像有必要对线程池拥有的线程数量进行限制,因为有些人觉得,要合理利用资源,做到自己调配资源,是很有成就感的事(是不是强迫症?)
但实践证明,线程池永远都不应该为池中的线程数设置上限,因为可能发生饥饿或死锁。
为什么这么说?
假如队列中有1000个工作项,但这些工作项全都因为一个事件而阻塞(多么可怕的事),等到第1001个工作项发出信号才能解除阻塞。如果设置最大1000个线程,第1001个线程就不会执行,所以1000个线程会一直阻塞,然后你能想到的,用户被迫终止应用程序,并丢失他们的所有未保存的工作。你不能让线程阻塞!
由于存在饥饿和死锁问题,所以CLR团队一直都在稳步的增加线程池默认能拥有的最大线程数。
目前默认值是最大1000个。这可以看成是不限数量,为什么?
一个32位进程最大的2GB的可用地址空间,加载了一组Win32和CLR DLLs,并分配了本地堆和托管堆之后,剩余约1.5GB的地址空间。由于每个线程都要为用户模式栈和线程环境块准备超过1MB的内存,所以在一个32位的进程中,最多能有1360个线程。试图创建更多线程,则会抛出OutMemoryException。
一个64位进程提供了8TB的地址空间,所以理论上可以创建千百万个线程。但是分配这么多线程,纯属浪费,尤其是当理想线程数等于机器的CPU数的时候。
ThreadPool类提供了几个静态方法,调用它们可以设置和查询线程池的线程数:GetMaxThreads,SetMaxThreads,GetMinThreads和GetAvailableThreads。这里建议你,不要调用上述任何方法,限制线程池的线程数,一般只会造成应用程序的性能变得更差,而不会变得更好。
如果你认为自己的应用程序需要几百个或者几千个线程,那只表明,你的应用程序的架构和使用线程的方式已出现严重的问题。
现在来看看如何管理工作者线程,之前需要来看看CLR线程池是什么样的:

这是工作者线程的数据结构。ThreadPool.QueueUserWorkItem方法和Timer类总是会将工作项放到全局队列中。
而工作线程采用一个先入先出(FIFO)算法将工作项从这个队列取出,并处理它们。(学过数据结构的应该知道FIFO)
由于多个工作者线程可能同时从全局队列中拿走工作项,所以所有工作者线程都竞争一个线程同步锁,以保证两个或多个线程不会获取同一个工作项。同步锁在某些应用程序总可能对伸缩性和性能造成某种程度的限制。
当一个非工作者线程调度一个Task时,Task会添加到全局队列。但是,每个工作者线程都有它自己的本地队列,上图可以看到,工作者线程是主,对应的本地队列是附,当一个工作者线程调度一个Task时,Task会添加到调用线程的本地队列,而不是全局队列。
现在来看下工作者线程的描述:
工作者线程之所以称为Workers,它是名副其实的。它就是一“工作狂”,打个比方:
工作狂是什么?做完自己的事还不够,还要去抢别人的事做,别人的事做完了,就去找公共的事做,除非没有事干,要不然不会停下。
用这个比方,下面我的介绍就会浅显很多了。
一个工作者线程准备处理一个工作项时,它总是先检查它的本地队列来查找一个Task。如果存在Task,工作者线程就从它的本地队列中移除Task,并对工作项进行处理。
要注意的是,工作者线程是采用一个“栈”式结构,也就是后入先出(LIFO)算法,将任务从它的本队队列中取出。由于工作者线程是唯一允许访问自己的本地队列头的线程,所以不需要同步锁,而且在队列中添加和删除任务的速度非常快,这个行为的副作用就是,它的执行顺序是相反的,后入的先执行。
还有哦,如果一个工作者线程发现本地队列变空了,那么它就会尝试从另一个工作者线程的本地队列中“偷”一个Task,并获取一个线程同步锁,不过这种情况还是很少发生的。
再是,当所有本地队列都为空了,工作者线程就使用FIFO算法,从全局队列中提取一个工作项,当然也会取得它的锁。
现在所有队列都为空了,工作者线程就会自己进入睡眠状态,等待事情的发生。如果睡眠了时间太长,它会自己醒来,并销毁自身。
线程池会快速创建工作者线程,工作者线程的数量等于ThreadPool的SetMinThreads方法的值(默认是你的电脑CPU数),32位进程最多用32个CPU,64位进程最多可用64个CPU。然后创建工作者线程达到机器CPU数时,线程池会监视工作项的完成速度,如果工作项完成的时间太长,线程池就会创建更多的工作者线程,使工作加速完成。如果工作项的完成速度开始变快了,工作者线程就会被销毁。
线程池的设计是很人性话的,有没有体会到?
线程基础用了这么久才介绍完,新的起点又来啦。^_^
C#线程篇---线程池如何管理线程(6完结篇)的更多相关文章
- C# 线程(二):关于线程的相关概念
From : http://kb.cnblogs.com/page/42528/ 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源. 而一个进程又 ...
- 【Linux 线程】同一个进程中的线程共享哪些资源
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线 ...
- C# 多线程的自动管理(线程池) 基于Task的方式
C# 多线程的自动管理(线程池) 在多线程的程序中,经常会出现两种情况: 1. 应用程序中线程把大部分的时间花费在等待状态,等待某个事件发生,然后给予响应.这一般使用 ThreadPool(线程 ...
- 使用ExecutorCompletionService 管理线程池处理任务的返回结果
在我们日常使用线程池的时候,经常会有需要获得线程处理结果的时候.此时我们通常有两种做法. 1. 使用并发容器将callable.call() 的返回Future存储起来.然后使用一个消费者线程去遍历这 ...
- ExecutorService实际上是一个线程池的管理工具
在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过Executor来启动线程比用 Thread的start()更好.在新特征 ...
- C#多线程学习(四) 多线程的自动管理(线程池)
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- Python之路(第四十六篇)多种方法实现python线程池(threadpool模块\multiprocessing.dummy模块\concurrent.futures模块)
一.线程池 很久(python2.6)之前python没有官方的线程池模块,只有第三方的threadpool模块, 之后再python2.6加入了multiprocessing.dummy 作为可以使 ...
- 线程池的管理类MyThreadPoolManager
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executor; import java.ut ...
- 如何应用CLR线程池来管理多线程
class Program { static void Main(string[] args) { int intWorkerT ...
随机推荐
- RabbitMQ理论部分
概念 queue 队列 exchange 交换机 bind 绑定 channel 通道 一个发送消息流程包含上述四个概念.消息经过channel传递给exc ...
- 6.openldap客户端安装
作者:yaoyao 1.账号登录系统流程讲解 当在客户端输入账号登录系统时.系统根据/etc/nsswitch.conf配置文件获取账号查找顺序,然后在根据pam配置文件调用相关模块,对账号/etc/ ...
- 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!
本文主要展示的是通过使用python和PyInstaller来构建恶意软件的一些poc. 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!众所周知的,恶意软件如果影响到了他人的生 ...
- CocoaPods did not set the base configuration of your project because your project already has a custom config set.
今天在封装自己的消息推送SDK的时候,pod install 的时候,突然报这个错误,解决方式如下: $ pod install Analyzing dependencies Downloading ...
- 利用cocoapods创建基于git的私有库Spec Repo
上一篇文章记录了我利用cocoapods创建基于SVN的私有库的全部过程,今天我再记录一下基于git创建的过程. 整体先说明一下创建一个私有的podspec包括如下那么几个步骤: 创建并设置一个私有的 ...
- NEWBEE软件团队 人员分配情况及分数获得方式
人员分配: PM:李桐 王骜 dev:王骜 刘垚鹏 安康 林旭鹏 黄新越 test:黄伟龙 李桐 马佐霖 黄新越 注:黄新越为女生,不方便平时的交流,所以任务分配较为灵活,特分在两个组里. 评分 ...
- [buaa-SE-2017]个人作业-回顾
个人作业-回顾 提问题的博客:[buaa-SE-2017]个人作业-Week1 Part1: 问题的解答和分析 1.1 问题:根据书中"除了前20的学校之外,计科和软工没有区别"所 ...
- SDPA: Toward a Stateful Data Plane in Software-Defined Networking
文章名称:SDPA: Toward a Stateful Data Plane in Software-Defined Networking 发表时间:2017 期刊来源:IEEE/ACM Trans ...
- “吃神么,买神么”的第一个Sprint计划(第四天)
“吃神么,买神么”项目Sprint计划 ——5.24 星期日(第四天)立会内容与进度 摘要:logo做出来了,但是在立会展示时遭到反对,不合格,重新设计.(附上失败的logo图) 目前搜索栏出来了, ...
- WCF 和 ASP.NET Web API
地址:https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/wcf-and-aspnet-web-api WCF 是 Microsoft 为生成面 ...