异步线程,线程池的选用

CL科雷傲线程池并不会在CLPAJERO初步化时立时成立线程,而是在应用程序要开创线程来运行任务时,线程池才开端化三个线程。
线程池开首化时是从未有过线程的,线程池里的线程的初始化与其他线程壹样,然则在形成职务之后,该线程不会活动销毁,而是以挂起的情景重返到线程池。直到应用程序再度向线程池发出请求时,线程池里挂起的线程就会再也激活执行职分。
如此那般既节省了建立线程所导致的属性损耗,也得以让七个任务反复重用同1线程,从而在应用程序生存期内节约大批量支付。

明天大家来谈谈线程池:

  怎么使用线程池?  

异步编制程序:使用线程池管理线程,异步线程

异步编制程序:使用线程池管理线程

亚洲必赢官网 1

 从此图中我们会发现 .NET 与C#
的各类版本宣布都以有八个“主旨”。即:C#一.0托管代码→C#2.0泛型→C#3.0LINQ→C#四.0动态语言→C#5.0异步编制程序。以后自小编为流行版本的“异步编制程序”宗旨写类别分享,期待你的查阅及点评。

 

现在的应用程序越来越复杂,我们常常须求动用《异步编制程序:线程概述及使用》中关系的四线程技术来抓好应用程序的响应速度。那时大家1再的创办和销毁线程来让应用程序火速响应操作,那频仍的创建和销毁无疑会下落应用程序质量,大家得以引入缓存机制化解那么些题目,此缓存机制亟待缓解如:缓存的轻重难题、排队执行职务、调度空闲线程、按需创立新线程及销毁多余空闲线程……近年来微软一度为大家提供了现成的缓存机制:线程池

        
线程池原自于对象池,在详细表达明线程池前让我们先来打探下何为对象池。

流程图:

 亚洲必赢官网 2

 

         对于对象池的清理平时设计二种办法:

1)         手动清理,即积极调用清理的艺术。

二)         自动清理,即由此System.Threading.Timer来实现定时清理。

 

重视实现代码:

 

  亚洲必赢官网 3public
sealed class ObjectPool<T> where T : ICacheObjectProxy<T> {
// 最大体量 private Int3二 m_maxPoolCount = 30; // 最小体量 private
Int32 m_minPoolCount = 伍; // 已存容积 private Int32 m_currentCount; //
空闲+被用 对象列表 private Hashtable m_listObjects; // 最大空闲时间
private int maxIdleTime = 120; // 定时清理对象池指标 private Timer timer
= null; /// <summary> /// 创制对象池 /// </summary> ///
<param name=”maxPoolCount”>最小容量</param> /// <param
name=”minPoolCount”>最大体量</param> /// <param
name=”create_params”>待创造的实际上指标的参数</param> public
ObjectPool(Int3贰 maxPoolCount, Int32 minPoolCount, Object[]
create_params){ } /// <summary> /// 获取1个对象实例 ///
</summary> ///
<returns>重回内部实际指标,若重临null则线程池已满</returns>
public T GetOne(){ } /// <summary> /// 释放该对象池 ///
</summary> public void Dispose(){ } /// <summary> ///
将对象池中钦定的靶子重置并设置为空闲状态 /// </summary> public
void ReturnOne(T obj){ } /// <summary> /// 手动清理对象池 ///
</summary> public void 马努alReleaseObject(){ } ///
<summary> /// 自动清理对象池(对超过 最小体量 的空闲对象实行放飞)
/// </summary> private void AutoReleaseObject(Object obj){ } }
完结的重要代码

 

通过对“对象池”的三个光景认识能帮我们更快掌握线程池。

 

线程池ThreadPool类详解

ThreadPool静态类,为应用程序提供叁个由系统一管理理的援助线程池,从而使您能够集中精力于应用程序任务而不是线程管理。各样进程都有二个线程池,多个Process中不得不有3个实例,它在各类应用程序域(AppDomain)是共享的。

在里边,线程池将团结的线程划分工作者线程(帮忙线程)和I/O线程。前者用于执行平日的操作,后者专用于异步IO,比如文件和网络请求,注意,分类并不表明三种线程自己有出入,内部依旧是相同的。

亚洲必赢官网 4public
static class ThreadPool { //
将操作系统句柄绑定到System.Threading.ThreadPool。 public static bool
BindHandle(SafeHandle osHandle); //
检索由ThreadPool.Get马克斯Threads(Int3二,Int3二)方法再次回到的最大线程池线程数和眼下活动线程数之间的差值。
public static void GetAvailableThreads(out int workerThreads , out int
completionPortThreads); //
设置和搜索能够同时处于活动状态的线程池请求的数额。 //
全部大于此数额的伸手将保险排队状态,直到线程池线程变为可用。 public
static bool Set马克斯Threads(int workerThreads, int completionPortThreads);
public static void Get马克斯Threads(out int workerThreads, out int
completionPortThreads); //
设置和检索线程池在新请求预测中保险的空闲线程数。 public static bool
SetMinThreads(int workerThreads, int completionPortThreads); public
static void GetMinThreads(out int workerThreads, out int
completionPortThreads); //
将艺术排入队列以便执行,并点名包罗该措施所用数据的指标。此格局在无线程池线程变得可用时进行。
public static bool QueueUserWorkItem(WaitCallback callBack, object
state); // 将重叠的 I/O 操作排队以便执行。若是成功地将此操作排队到 I/O
完结端口,则为 true;不然为 false。 //
参数overlapped:要排队的System.Threading.NativeOverlapped结构。 public
static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped);
// 将点名的嘱托排队到线程池,但不会将调用堆栈传播到劳引力线程。 public
static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object
state); // 注册三个等待Threading.WaitHandle的寄托,并点名二个 三1九人有标志整数来表示超时值(以纳秒为单位)。 // executeOnlyOnce假诺为
true,表示在调用了信托后,线程将不再在waitObject参数上等待; // 尽管为
false,表示每趟完成等待操作后都重置计时器,直到撤消等待。 public static
RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject
, WaitOrTimerCallback callBack, object state, Int
millisecondsTimeOutInterval, bool executeOnlyOnce); public static
RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle
waitObject , WaitOrTimerCallback callBack , object state , int
milliseconds提姆eOutInterval , bool executeOnlyOnce); …… } ThreadPool

一)         使用Get马克斯Threads()和Set马克斯Threads()获取和设置最大线程数

可排队到线程池的操作数仅受内部存款和储蓄器的范围;而线程池限制进度中能够而且处于活动状态的线程数(默许情形下,限制各样CPU 能够接纳 25 个工作者线程和 1,000 个 I/O 线程(依照机器CPU个数和.net
framework版本的不等,那几个多少恐怕会有生成)),全数大于此数据的请求将保持排队状态,直到线程池线程变为可用。

不提出更改线程池中的最大线程数:

a)        
将线程池大小设置得太大,恐怕会造成更频仍的履行上下文切换及深化财富的争用境况。

b)        
其实FileStream的异步读写,异步发送接受Web请求,System.Threading.Timer定时器,甚至使用delegate的beginInvoke都会暗许调用
ThreadPool,约等于说不仅你的代码大概利用到线程池,框架之中也或者采取到。

c)        
叁个运用程序池是一个单独的进度,拥有贰个线程池,应用程序池中得以有七个WebApplication,各个运维在2个单身的AppDomain中,这几个WebApplication公用两个线程池。

 

2)         使用GetMinThreads()和SetMinThreads()获取和安装最小空闲线程数

为防止向线程分配不供给的仓库空间,线程池依据一定的时日距离成立新的空闲线程(该区间为半秒)。所以要是最小空闲线程数设置的过小,在长期内执行大气职分会因为创建新空闲线程的放权延迟导致质量瓶颈。最小空闲线程数暗许值等于机械上的CPU核数,并且不建议改变最小空闲线程数。

在运营线程池时,线程池具有二个放权延迟,用于启用最小空闲线程数,以抓牢应用程序的吞吐量。

在线程池运转中,对于推行完职务的线程池线程,不会应声销毁,而是再次来到到线程池,线程池会维护最小的空闲线程数(尽管应用程序所无线程都是悠闲状态),以便队列职务可以立即运转。当先此最小数指标悠闲线程1段时间没事做后会自身醒来终止本人,以节省系统财富。

三)         静态方法GetAvailableThreads()

透过静态方法GetAvailableThreads()重返的线程池线程的最大数据和当前移动数量之间的差值,即获取线程池中当前可用的线程数目

四)         八个参数

办法Get马克斯Threads()、Set马克斯Threads()、GetMinThreads()、SetMinThreads()、GetAvailableThreads()钧蕴含五个参数。参数workerThreads指工作者线程;参数completionPortThreads指异步
I/O 线程。

通过调用 ThreadPool.QueueUserWorkItem 并传递 WaitCallback
委托来使用线程池。也足以经过行使 ThreadPool.RegisterWaitForSingleObject
并传递 WaitHandle(在向其发出复信号或过期时,它将掀起对由
WaitOrTimerCallback
委托包装的不贰法门的调用)来将与等待操作相关的行事项排队到线程池中。若要废除等待操作(即不再执行WaitOrTimerCallback委托),可调用RegisterWaitForSingleObject()方法重临的RegisteredWaitHandle的
Unregister 方法。

只要你领悟调用方的仓库与在排队职务执行时期推行的装有平安检查不相干,则仍是能够使用不安全的法门ThreadPool.UnsafeQueueUserWorkItem 和
ThreadPool.UnsafeRegisterWaitForSingleObject。QueueUserWorkItem 和
RegisterWaitForSingleObject
都会捕获调用方的仓库,此堆栈将在线程池线程开头施行职责时合并到线程池线程的仓库中。假使急需开始展览安检,则必须检查整个堆栈,但它还兼具自然的属性费用。使用“不安全的”方法调用并不会提供相对的平安,但它会提供更好的性格。

让2个线程不鲜明地守候贰个内核查象进入可用状态,那对线程的内部存款和储蓄器能源来说是一种浪费。ThreadPool.RegisterWaitForSingleObject()为大家提供了一种艺术:在三个基础对象变得可用的时候调用3个措施。

动用需注意:

壹)         WaitOrTimerCallback委托参数,该信托接受一个名称为timeOut的Boolean参数。若是 WaitHandle 在钦定时间内未有吸收频限信号(即,超时),则为true,不然为 false。回调方法能够依据timeOut的值来针对地采用措施。

2)         名称为executeOnlyOnce的Boolean参数。传true则象征线程池线程只实行回调方法一遍;若传false则代表内核查象每便收到连续信号,线程池线程都会实施回调方法。等待二个AutoReset伊夫nt对象时,那几个意义越来越有用。

3)         RegisterWaitForSingleObject()方法重返2个RegisteredWaitHandle对象的引用。那么些目的标识了线程池正在它上边等待的基本对象。大家得以调用它的Unregister(WaitHandle
waitObject)方法撤销由RegisterWaitForSingleObject()注册的等待操作(即WaitOrTimerCallback委托不再实施)。Unregister(WaitHandle
waitObject)的WaitHandle参数表示成功裁撤注册的守候操作后线程池会向此指标发出非确定性信号(set()),若不想接收此公告能够传递null。

         示例:

亚洲必赢官网 5private
static void Example_RegisterWaitForSingleObject() { //
加endWaitHandle的缘由:若是推行过快退出方式会造成壹些事物被保释,造成排队的职务无法履行,原因还在商讨AutoReset伊芙nt endWaitHandle = new AutoReset伊芙nt(false); AutoResetEvent
notificWaitHandle = new AutoReset伊夫nt(false); AutoReset伊夫nt waitHandle
= new AutoReset伊芙nt(false); RegisteredWaitHandle registeredWaitHandle =
ThreadPool.RegisterWaitForSingleObject( waitHandle, (Object state, bool
timedOut) => { if (timedOut)
Console.WriteLine(“RegisterWaitForSingleObject因超时而执行”); else
Console.WriteLine(“RegisterWaitForSingleObject收到WaitHandle时域信号”); },
null, 提姆eSpan.FromSeconds(贰), true ); //
撤消等待操作(即不再实施WaitOrTimerCallback委托)
registeredWaitHandle.Unregister(notificWaitHandle); // 通告ThreadPool.RegisterWaitForSingleObject( notificWaitHandle, (Object
state, bool timedOut) => { if (timedOut)
Console.WriteLine(“第贰个RegisterWaitForSingleObject没有调用Unregister()”);
else
Console.WriteLine(“第一个RegisterWaitForSingleObject调用了Unregister()”);
endWaitHandle.Set(); }, null, TimeSpan.FromSeconds(肆), true );
endWaitHandle.WaitOne(); } 示例

推行上下文

        
上一小节中提及:线程池最大线程数设置过大可能会导致Windows频仍执行上下文切换,下降程序品质。对于大多数园友不会满足那样的答复,作者和您一样也喜欢“知其然,再知其所以然”。

.NET中上下文太多,小编最后得出的定论是:上下文切换中的上下文专指“执行上下文”。

实施上下文包涵:安全上下文、同步上下文(System.Threading.SynchronizationContext)、逻辑调用上下文(System.Runtime.Messaging.CallContext)。即:安全设置(压缩栈、Thread的Principal属性和Windows身份)、宿主设置(System.Threading.HostExcecutingContextManager)以及逻辑调用上下文数据(System.Runtime.Messaging.CallContext的LogicalSetData()和LogicalGetData()方法)。

当3个“时间片”甘休时,假使Windows决定重新调度同3个线程,那么Windows不会执行上下文切换。假使Windows调度了一个见仁见智的线程,这时Windows执行线程上下文切换。

        
当Windows上下文切换成另1个线程时,CPU将进行一个比不上的线程,而此前线程的代码和数码还在CPU的高速缓存中,(高速缓存使CPU不必平日访问RAM,RAM的快慢比CPU高速缓存慢得多),当Windows上下文切换成多少个新线程时,那几个新线程极有极大大概要实施不一致的代码并访问分裂的数码,这几个代码和数码不在CPU的高速缓存中。由此,CPU必须访问RAM来填充它的高速缓存,以回复十分的快实市场价格况。不过,在其“时间片”执行完后,一回新的线程上下文切换又产生了。

上下文切换所产生的支出不会换成任何内部存款和储蓄器和属性上的纯收入。执行上下文所需的光阴取决于CPU架构和进程(即“时间片”的分红)。而填充CPU缓存所需的年华取决于系统运作的应用程序、CPU、缓存的分寸以及别的各类因素。所以,不可能为每三次线程上下文切换的年月支出给出2个规定的值,甚至无法提交五个估算的值。唯一分明的是,若是要构建高品质的应用程序和组件,就应当尽大概防止线程上下文切换。

除去,执行垃圾回收时,CLLAND必须挂起(暂停)全部线程,遍历它们的栈来查找根以便对堆中的对象举行标记,再一次遍历它们的栈(有的对象在减小时期产生了活动,所以要立异它们的根),再复苏所无线程。所以,收缩线程的数目也会肯定升级垃圾回收器的品质。每一回使用3个调节和测试器并碰着贰个断点,Windows都会挂起正在调节和测试的应用程序中的全部线程,并在单步执行或运转应用程序时上涨全数线程。由此,你用的线程越来越多,调节和测试体验也就越差。

Windows实际记录了各样线程被上下文切换来的次数。能够选拔像Microsoft
Spy++这样的工具查看这一个数量。这么些工具是Visual
Studio附带的二个小工具(vs按安装路径\Visual Studio
2012\Common7\Tools),如图

亚洲必赢官网 6

在《异步编制程序:线程概述及运用》中本身提到了Thread的七个上下文,即:

一)         CurrentContext       
获取线程正在内部实施的当前上下文。主要用以线程内部存款和储蓄数据。

贰)         ExecutionContext   
获取二个System.Threading.ExecutionContext对象,该指标涵盖关于当前线程的各样上下文的新闻。首要用于线程间数据共享。

里面获得到的System.Threading.ExecutionContext正是本小节要说的“执行上下文”。

亚洲必赢官网 7public
sealed class ExecutionContext : IDisposable, ISerializable { public void
Dispose(); public void GetObjectData(SerializationInfo info,
StreamingContext context); //
此措施对于将履行上下文从三个线程传播到另1个线程万分管用。 public
ExecutionContext CreateCopy(); // 从日前线程捕获执行上下文的3个副本。
public static ExecutionContext Capture(); //
在当前线程上的钦命执行上下文中运作有些方法。 public static void
Run(ExecutionContext executionContext, ContextCallback callback, object
state); // 打消执行上下文在异步线程之间的流淌。 public static
AsyncFlowControl SuppressFlow(); public static bool IsFlowSuppressed();
// RestoreFlow 撤销以前的 SuppressFlow 方法调用的熏陶。 // 此形式由
SuppressFlow 方法重回的 AsyncFlowControl 结构的 Undo 方法调用。 //
应利用 Undo 方法(而不是 RestoreFlow 方法)恢复生机执行上下文的流动。 public
static void RestoreFlow(); } View
Code

ExecutionContext
类提供的职能让用户代码能够在用户定义的异步点之间捕获和传导此上下文。公共语言运维时(CL哈弗)确认保证在托管进度内运维时定义的异步点之间平等地传输
ExecutionContext。

异步线程,线程池的选用。每当二个线程(初始线程)使用另三个线程(补助线程)执行义务时,CLMurano会将前者的实践上下文流向(复制到)援救线程(注意那几个活动流向是单方向的)。那就保障了援助线程执行的任何操作使用的是相同的安全设置和宿主设置。还担保了开始线程的逻辑调用上下文能够在支援线程中动用。

但施行上下文的复制会招致一定的属性影响。因为执行上下文中包涵大批量音信,而采访全部这一个音信,再把它们复制到支持线程,要花费成千上万年华。要是支持线程又采取了越多地协理线程,还必须创造和先导化越来越多的施行上下文数据结构。

故此,为了进步应用程序质量,大家得以阻挡实施上下文的流淌。当然那唯有在支援线程不供给恐怕不访问上下文新闻的时候才能拓展拦截。

下边给出多少个演示为了演示:

1)         在线程间共享逻辑调用上下文数据(CallContext)。

二)         为了进步品质,阻止\卷土重来执行上下文的流淌。

三)         在当前线程上的钦命执行上下文中运作某些方法。

亚洲必赢官网 8private
static void Example_ExecutionContext() {
CallContext.LogicalSetData(“Name”, “小红”);
Console.WriteLine(“主线程中Name为:{0}”,
CallContext.LogicalGetData(“Name”)); // 一)
在线程间共享逻辑调用上下文数据(CallContext)。
Console.WriteLine(“一)在线程间共享逻辑调用上下文数据(CallContext)。”);
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500);
Console.WriteLine(); // 二) 为了进步品质,废除\恢复生机执行上下文的流动。
ThreadPool.UnsafeQueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程使用Unsafe异步执行格局来撤废执行上下文的流动。Name为:\”{0}\””
, CallContext.LogicalGetData(“Name”)), null);
Console.WriteLine(“二)为了提高质量,撤消/恢复生机执行上下文的流动。”);
AsyncFlowControl flowControl = ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“(废除ExecutionContext流动)ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500); //
復苏不推荐使用ExecutionContext.RestoreFlow() flowControl.Undo();
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“(复苏ExecutionContext流动)ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500);
Console.WriteLine(); // 叁)
在此时此刻线程上的内定执行上下文中运作有些方法。(通过得到调用上下文数据申明)
Console.WriteLine(“三)在近期线程上的钦命执行上下文中运作有个别方法。(通过得到调用上下文数据印证)”);
ExecutionContext curExecutionContext = ExecutionContext.Capture();
ExecutionContext.SuppressFlow(); ThreadPool.QueueUserWorkItem( (Object
obj) => { ExecutionContext innerExecutionContext = obj as
ExecutionContext; ExecutionContext.Run(innerExecutionContext, (Object
state) =>
Console.WriteLine(“ThreadPool线程中Name为:\”{0}\””<br> ,
CallContext.LogicalGetData(“Name”)), null); } , curExecutionContext ); }
View Code

结果如图:

亚洲必赢官网 9

 

 

 注意:

一)        
示例中“在近来线程上的内定执行上下文中运转有些方法”:代码中务必使用ExecutionContext.Capture()获取当前履行上下文的一个副本

a)        
若直接行使Thread.CurrentThread.ExecutionContext则会报“不只怕运用以下上下文:
跨 AppDomains 封送的上下文、不是因而捕获操作获取的上下文或已当做 Set
调用的参数的上下文。”错误。

b)        
若使用Thread.CurrentThread.ExecutionContext.CreateCopy()会报“只可以复制新近捕获(ExecutionContext.Capture())的上下文”。

2)        
撤废执行上下文流动除了使用ExecutionContext.SuppressFlow()情势外。还是能透过利用ThreadPool的UnsafeQueueUserWorkItem

UnsafeRegisterWaitForSingleObject来实施委托方法。原因是不安全的线程池操作不会传导压缩堆栈。每当压缩堆栈流动时,托管的器重点、同步、区域安装和用户上下文也跟着流动。

 

线程池线程中的相当

线程池线程中未处理的尤其将适可而止进度。以下为此规则的二种例外景况: 

  1. 鉴于调用了 Abort,线程池线程上将掀起ThreadAbortException。 
    2.
    是因为正在卸载应用程序域,线程池线程中校引发AppDomainUnloadedException。 
  2. 国有语言运转库或宿主进程将截至线程。

什么时候不使用线程池线程

现今大家都早已知道线程池为咱们提供了方便人民群众的异步API及托管的线程管理。那么是或不是其它时候都应有使用线程池线程呢?当然不是,大家依然须求“因地制宜”的,在以下两种景况下,适合于创建并管制本人的线程而不是使用线程池线程:

 

 

  本博文介绍线程池以及其基础对象池,ThreadPool类的应用及注意事项,怎么样排队办事项到线程池,执行上下文及线程上下文字传递递难题…… 

线程池固然为我们提供了异步操作的方便,然而它不支持对线程池中单个线程的复杂性控制致使我们某个情状下会直接使用Thread。并且它对“等待”操作、“废除”操作、“一而再”职分等操作相比较麻烦,或许驱使你从新造轮子。微软也想到了,所以在.NET4.0的时候进入了“并行任务”并在.NET四.5中对其展开改进,想打听“并行职责”的园友能够先看看《(译)关于Async与Await的FAQ》。

本节到此甘休,谢谢大家的玩味。赞的话还请多引进啊 (*^_^*)

 

 

 

 

参考资料:《CL智跑 via C#(第三版)》

 

 摘自:

 

亚洲必赢官网,
异步编制程序:使用线程池管理线程 从此图中大家会发现 .NET 与C#
的各样版本公布都以有一个宗旨…

透过CL大切诺基线程池所确立的线程总是私下认可为后台线程,优先级数为ThreadPriority.Normal。

应用程序能够有多少个线程,这么些线程在蛰伏状态中必要消耗大量时间来等待事件产生。其余线程恐怕进入睡眠景况,并且仅定期被晋升以轮循更改或更新境况音信,然后再一次进入休眠状态。为了简化对那么些线程的治本,.NET框架为各种进度提供了贰个线程池,三个线程池有几几个等待操作情形,当八个等候操作达成时,线程池中的支持线程会执行回调函数。线程池中的线程由系统一管理理,程序员不须要费劲于线程管理,能够集中精力处理应用程序职务。通过基础类库中的ThreadPool类提供一个线程池,该线程池可用来发送工作现,处理异步I/O,代表任何线程等待及处理计时器.ThreadPool类的富有办法都以静态方法.ThreadPool本人也是3个静态类.
大家来探望她的定义和1些常用的主意:
 public
static class ThreadPool
{
 [SecuritySafeCritical]
        public static void
GetAvailableThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static void
GetMaxThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static void
GetMinThreads(out int workerThreads, out int
completionPortThreads);
        [SecuritySafeCritical]
        public static bool
QueueUserWorkItem(WaitCallback callBack);
        [SecuritySafeCritical]
        public static bool
QueueUserWorkItem(WaitCallback callBack, object state);
}
GetAvailableThreads这些方法重回的最大线程池线程数和脚下活动线程数之间的差值。
参数 workerThreads: 可用扶助线程的多少。completionPortThreads: 可用异步
I/O 线程的多寡。
Get马克斯Threads方法赢稳妥前由线程池维护的赞助线程的最大数目.参数
workerThreads: 线程池中国救亡剧团助线程的最大数目。completionPortThreads:
当前由线程池维护的闲暇异步 I/O 线程的最大数据。
GetMinThreads方法赢妥善前由线程池维护的空闲帮助线程的矮小数目.参数
workerThreads:
当前由线程池维护的悠闲协助线程的蝇头数目.completionPortThreads:
当前由线程池维护的闲暇异步 I/O 线程的微乎其微数目。
QueueUserWorkItem方法将艺术排入队列以便执行。参数callBack,
表示要实施的方法.state:包括方法所用数据的靶子。
上边看个例证:

  在面向对象编制程序中,创设和销毁对象是很费时间的,因为成立叁个对象要获得内部存款和储蓄器财富依旧其它更加多财富,所以加强服务程序效能的贰个一手正是尽恐怕缩短创制和销毁对象的次数,尤其是一些很耗财富的对象成立和销毁。怎么样利用已有指标来服务正是2个索要缓解的关键难题,其实这正是有的”池化能源”技术发生的原由。比如大家所熟稔的数据库连接池便是遵照这一心想而产生的,本文将介绍的线程池技术壹样符合这一思索。

CL安德拉线程池分为劳力线程(workerThreads)I/O线程(completionPortThreads)两种:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 
 7 namespace ConsoleApplication6
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             Console.WriteLine("主线程进行异步条用");
14 
15             AutoResetEvent asyncOpIsDone = new AutoResetEvent(false);
16             ThreadPool.QueueUserWorkItem(new WaitCallback((x) =>
17             {
18 
19                 Thread.Sleep(1000);
20                 Console.WriteLine("工作任务");
21 
22             }));
23             string s="我的参数";
24             ThreadPool.QueueUserWorkItem(new WaitCallback((x) =>
25             {
26                
27                 Thread.Sleep(2000);
28                 Console.WriteLine("工作任务1");
29                 Console.WriteLine(x);
30                
31             }), s);
32             ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation), asyncOpIsDone);
33             Console.WriteLine("主线程执行其他");
34             Console.WriteLine("主线程等待任务处理结束");
35             asyncOpIsDone.WaitOne();
36         }
37         static void MyAsyncOperation(Object state)
38         {
39            
40             Thread.Sleep(5000);
41             Console.WriteLine("工作任务2");
42             ((AutoResetEvent)state).Set();
43         }
44     }
45 }

  • 劳力线程是重要用作管理CL景逸SUV内部对象的运维,普普通通用于总括密集的任务。
  • I/O(Input/Output)线程首要用来与外部系统相互消息,如输入输出,CPU仅需在职责开首的时候,将职务的参数字传送递给配备,然后运营硬件装置即可。等职务到位的时候,CPU收到3个文告,①般的话是三个硬件的间歇功率信号,此时CPU继续后继的处理工科作。在处理进度中,CPU是无须完全加入处理进度的,若是正在运营的线程不交出CPU的控制权,那么线程也只可以处于等候情形,就算操作系统将眼下的CPU调度给其余线程,此时线程所占有的长空依旧被占用,而并不曾CPU处理那些线程,大概出现线程资源浪费的难点。倘使那是2个网络服务程序,各个网络连接都采取一个线程管理,或许现身大量线程都在等候互连网通讯,随着网络连接的穿梭充实,处于等候情形的线程将会很开销尽全部的内部存款和储蓄器财富。能够思索使用线程池化解那几个标题。

 

  十贰线程是哪些?组成?特点?

  线程池的最大值壹般默许为一千、三千。当不止此数量的恳求时,将保持排队状态,直到线程池里有线程可用。

 运转的结果为

  线程池是壹种十二线程处理方式,处理进程中校任务添加到行列,然后在成立线程后活动运行那个职分。线程池中的线程由系统一管理理,程序员不需求费劲于线程管理,能够集中精力处理应用程序任务。

  使用CL逍客线程池的劳重力线程①般有二种情势:

亚洲必赢官网 10

  组成:服务器程序利用线程技术响应客户请求已经司空见惯,或然你觉得这么做效用已经很高,但您有未有想过优化一下使用线程的不二秘籍。该小说将向您介绍服务器程序怎么着利用线程池来优化质量并提供三个简易的线程池完成。

  • 通过ThreadPool.QueueUserWorkItem()方法;
  • 通过委托;

此处有个类为AutoReset伊夫nt,他的效益是通报正在等候的线程已发出事变。他是从伊夫ntWaitHandle继承而来的!例子中分头用了两种分化的法子调用,第二种是能够传递参数的!工作线程1就传递了”小编的参数”字符串!工作线程二运作完了会布告等待的线程已产闹事件.那里AutoReset伊夫nt开首化的时候首先将复信号设成false,工作线程二比方调用成功,将被设成true. asyncOpIsDone.WaitOne()阻塞当前线程,直到收到时域信号!

  一、线程池管理器(ThreadPoolManager):用于成立并管理线程池

  要专注,不论是经过ThreadPool.QueueUserWorkItem()照旧委托,调用的都以线程池里的线程。

再看下边包车型地铁事例

  二、工作线程(WorkThread): 线程池中线程

透过以下多少个方式能够读取和安装CL宝马7系线程池浙江中华工程集团作者线程与I/O线程的最大线程数。

 

  3、任务接口(Task):每一种任务必须贯彻的接口,以供工作线程调度任务的实行。

  1. ThreadPool.GetMax(out in workerThreads,out int
    completionPortThreads);
  2. ThreadPool.SetMax(int workerThreads,int completionPortThreads);

 

  四、职分队列:用于存放未有处理的天职。提供一种缓冲机制。

  若想测试线程池中有微微线程正在投入使用,能够透过ThreadPool.GetAvailableThreads(out
in workThreads,out int conoletionPortThreads)方法。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 
 7 namespace ConsoleApplication7
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
14             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
15             int workerThreads;
16             int completionPortThreads;
17 
18             AutoResetEvent asyncOpIsDone = new AutoResetEvent(false);//信号初始为空
19             AutoResetEvent asyncOpIsDone2 = new AutoResetEvent(false);
20             ThreadPool.QueueUserWorkItem(new WaitCallback(MyWork), asyncOpIsDone);
21             ThreadPool.QueueUserWorkItem(new WaitCallback(MyWork1), asyncOpIsDone2);
22             ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
23             Console.WriteLine("得当前由线程池维护的辅助线程的最大数目:{0}", workerThreads);
24             ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
25             Console.WriteLine("得当前由线程池维护的空闲辅助线程的最小数目:{0}", workerThreads);
26             /*WaitHandle[] waithandles = new WaitHandle[2];
27             waithandles[0] = asyncOpIsDone;
28             waithandles[1] = asyncOpIsDone2;
29             WaitHandle.WaitAll(waithandles);  */     
30             //或者可以这样
31             asyncOpIsDone.WaitOne();
32             Console.WriteLine("MyWork结束");
33             asyncOpIsDone2.WaitOne();
34             Console.WriteLine("MyWork1结束");
35         }
36         static void MyWork(Object state)
37         {
38             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
39             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
40             Thread.Sleep(2000);
41             ((AutoResetEvent)state).Set();//表示工作已经完成
42         }
43         static void MyWork1(Object state)
44         {
45             Console.WriteLine("\n当前线程的HashCode:{0}", Thread.CurrentThread.GetHashCode().ToString());
46             Console.WriteLine("当前应用域的名字为:{0}", AppDomain.CurrentDomain.FriendlyName);
47             Thread.Sleep(1000);
48             ((AutoResetEvent)state).Set();//表示工作已经完成
49         }
50 
51     }
52 }

 

方法 说明
GetAvailableThreads 剩余空闲线程数
GetMaxThreads 最多可用线程数,所有大于此数目的请求将保持排队状态,直到线程池线程变为可用
GetMinThreads 检索线程池在新请求预测中维护的空闲线程数
QueueUserWorkItem 启动线程池里得一个线程(队列的方式,如线程池暂时没空闲线程,则进入队列排队)
SetMaxThreads 设置线程池中的最大线程数
SetMinThreads 设置线程池最少需要保留的线程数

 

  特点:

我们可以使用线程池来消除地点的大部难题,跟使用单个线程比较,使用线程池有如下优点:

运作结果为

  • 3个进度有且只有1个线程池。
  • 线程池线程都以后台线程(即不会堵住进度的告壹段落)
  • 每个线程都使用默许堆栈大小,以默许的事先级运维,并处在102线程单元中。超越最大值的别的线程需求排队,但它们要等到别的线程完结后才开动。
  • 在CL奥迪Q伍 二.0 SP一此前的本子中,线程池中 私下认可最大的线程数量 = 处理器数 *
    2伍, CL凯雷德 2.0 SP1之后就改为了 暗许最大线程数量 = 处理器数 *
    250,线程上限能够更改,通过使用ThreadPool.Get马克斯+Threads和ThreadPool.SetMaxThreads方法,能够获得和设置线程池的最大线程数。
  • 默许景况下,各类处理器维持三个悠然线程,即默许最小线程数 =
    处理器数。
  • 当过程运营时,线程池并不会自动创立。当第三回将回调方法排入队列(比如调用ThreadPool.QueueUserWorkItem方法)时才会创造线程池。
  • 在对3个干活项实行排队之后将不能够撤销它。
  • 线程池中线程在成功职分后并不会自行销毁,它会以挂起的情事重回线程池,假诺应用程序再一次向线程池发出请求,那么这些挂起的线程将激活并实施职务,而不会创立新线程,那将节省了不少支付。只无线程达到最大线程数量,系统才会以一定的算法销毁回收线程。

一、裁减应用程序的响应时间。因为在线程池中无线程的线程处于等候分配职分状态(只要未有超越线程池的最大上限),无需创造线程。

 


二、不必管理和护卫生活周期短暂的线程,不用在开登时为其分配财富,在其执行完职务之后自由财富。

亚洲必赢官网 11

  如何时候使用线程池?**  **

三、线程池会遵照近日系统特性对池内的线程举办优化处理。

本例中能够详细看AutoRest伊夫nt的用法MyWork壹其实先停止的,不过asyncOpIsDone供给等MyWork的实信号!所以先输出了MyWork结束.那里还有一个事物本人想说的便是WaitHandle,上边的例子已经交付了他的用法!他是AutoRsetEvent的基类.

  一、必要大批量的线程来形成职责,且实现任务的时日相比短。
WEB服务器实现网页请求那样的天职,使用线程池技术是很是合适的。因为单个任务小,而义务数量巨大,你能够设想一个看好网址的点击次数。
但对于长日子的义务,比如一个Telnet连接请求,线程池的优点就不明朗了。因为Telnet会话时间比线程的创办时间基本上了。

总之使用线程池的法力就是压缩制造和销毁线程的种类开发。在.NET中有一个线程的类ThreadPool,它提供了线程池的田管。

再有ThreadPool有贰个函数RegisterWaitForSingleObject这些函数依然满有意思的!笔者那里就不再给出例子了!

  二、对品质须要苛刻的应用,比如需要服务器神速响应客户请求。

ThreadPool是二个静态类,它从未构造函数,对外提供的函数也整整是静态的。当中有2个QueueUserWorkItem方法,它有三种重载方式,如下:

好了,后天就到这了!

  三、接受突发性的大度请求,但未必使服务器因而发生大量线程的应用。突发性大量客户请求,在未有线程池情形下,将产生多量线程,即使理论上多数操作系统线程数目最大值不是题材,长时间内发出多量线程大概使内部存储器到达终点,并现身”OutOfMemory”的百无一用。

public static bool QueueUserWorkItem(WaitCallback
callBack):将艺术排入队列以便执行。此方法在有线程池线程变得可用时实施。

    

public static bool QueueUserWorkItem(WaitCallback
callBack,Object
state):将艺术排入队列以便执行,并点名包罗该措施所用数据的目的。此格局在有线程池线程变得可用时举行。

  什么样时候不符合使用线程池?

QueueUserWorkItem方法中利用的的WaitCallback参数表示二个delegate,它的宣示如下:

  

public delegate void WaitCallback(Object
state)

  ●假若急需使三个职责具有一定优先级

借使供给传递任务新闻方可选择WaitCallback中的state参数,类似于ParameterizedThreadStart委托。

  ●要是持有希望会短期运作(并为此阻塞其余职分)的职分

上面是二个ThreadPool的例子,代码如下:

  ●要是须求将线程放置到单线程单元中(线程池中的线程均处于二十十二线程单元中)

亚洲必赢官网 12亚洲必赢官网 13

  ●假如要求永久标识来标识和操纵线程,比如想利用专用线程来终止该线程,将其挂起或按名称发现它。

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class ThreadPoolDemo
    {
        public ThreadPoolDemo()
        {
        }

        public void Work()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(CountProcess));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetEnvironmentVariables));
        }
        /// <summary>  
        /// 统计当前正在运行的系统进程信息  
        /// </summary>  
        /// <param name="state"></param>  
        private void CountProcess(object state)
        {
            Process[] processes = Process.GetProcesses();
            foreach (Process p in processes)
            {
                try
                {
                    Console.WriteLine("进程信息:Id:{0},ProcessName:{1},StartTime:{2}", p.Id, p.ProcessName, p.StartTime);
                }
                catch (Win32Exception e)
                {
                    Console.WriteLine("ProcessName:{0}", p.ProcessName);
                }
                finally
                {
                }
            }
            Console.WriteLine("获取进程信息完毕。");
        }
        /// <summary>  
        /// 获取当前机器系统变量设置  
        /// </summary>  
        /// <param name="state"></param>  
        public void GetEnvironmentVariables(object state)
        {
            IDictionary list = System.Environment.GetEnvironmentVariables();
            foreach (DictionaryEntry item in list)
            {
                Console.WriteLine("系统变量信息:key={0},value={1}", item.Key, item.Value);
            }
            Console.WriteLine("获取系统变量信息完毕。");
        }
    }
}

ThreadPoolDemo

  线程池常用艺术介绍?

亚洲必赢官网 14亚洲必赢官网 15

  

using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            ThreadPoolDemo tpd1 = new ThreadPoolDemo();
            tpd1.Work();
            Thread.Sleep(5000);
            Console.WriteLine("OK");
            Console.ReadLine();
        }
    }
}

  一、Get马克斯Threads()    :
 获取能够同时处于活动状态的线程池请求的最大数额。全部大于此数量的乞请将保持排队意况,直到线程池线程变为可用。

Program

    •   函数原型:public static void Get马克斯Threads (out int
      workerThreads,out int completionPortThreads)

 

                  参数壹:workerThreads
:线程池中扶植线程的最大数量。 
                  参数二:completionPortThreads :线程池中异步 I/O
线程的最大数量。 

采用ThreadPool调用工作线程和IO线程的范例

 

亚洲必赢官网 16亚洲必赢官网 17

  2、GetMinThreads()    获取线程池维护的细小空闲线程数。        

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            // 设置线程池中处于活动的线程的最大数目
            // 设置线程池中工作者线程数量为1000,I/O线程数量为1000
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main Thread: queue an asynchronous method");
            PrintMessage("Main Thread Start");

            // 把工作项添加到队列中,此时线程池会用工作者线程去执行回调方法            
            ThreadPool.QueueUserWorkItem(asyncMethod);
            asyncWriteFile();
            Console.Read();
        }

        // 方法必须匹配WaitCallback委托
        private static void asyncMethod(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous Method");
            Console.WriteLine("Asynchoronous thread has worked ");
        }


        #region 异步读取文件模块
        private static void asyncReadFile()
        {
            byte[] byteData = new byte[1024];
            FileStream stream = new FileStream(@"D:\123.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);
            //把FileStream对象,byte[]对象,长度等有关数据绑定到FileDate对象中,以附带属性方式送到回调函数
            Hashtable ht = new Hashtable();
            ht.Add("Length", (int)stream.Length);
            ht.Add("Stream", stream);
            ht.Add("ByteData", byteData);

            //启动异步读取,倒数第二个参数是指定回调函数,倒数第一个参数是传入回调函数中的参数
            stream.BeginRead(byteData, 0, (int)ht["Length"], new AsyncCallback(Completed), ht);
            PrintMessage("asyncReadFile Method");
        }

        //实际参数就是回调函数
        static void Completed(IAsyncResult result)
        {
            Thread.Sleep(2000);
            PrintMessage("asyncReadFile Completed Method");
            //参数result实际上就是Hashtable对象,以FileStream.EndRead完成异步读取
            Hashtable ht = (Hashtable)result.AsyncState;
            FileStream stream = (FileStream)ht["Stream"];
            int length = stream.EndRead(result);
            stream.Close();
            string str = Encoding.UTF8.GetString(ht["ByteData"] as byte[]);
            Console.WriteLine(str);
            stream.Close();
        }
        #endregion

        #region 异步写入文件模块
        //异步写入模块
        private static void asyncWriteFile()
        {
            //文件名 文件创建方式 文件权限 文件进程共享 缓冲区大小为1024 是否启动异步I/O线程为true
            FileStream stream = new FileStream(@"D:\123.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);
            //这里要注意,如果写入的字符串很小,则.Net会使用辅助线程写,因为这样比较快
            byte[] bytes = Encoding.UTF8.GetBytes("你在他乡还好吗?");
            //异步写入开始,倒数第二个参数指定回调函数,最后一个参数将自身传到回调函数里,用于结束异步线程
            stream.BeginWrite(bytes, 0, (int)bytes.Length, new AsyncCallback(Callback), stream);
            PrintMessage("AsyncWriteFile Method");
        }

        static void Callback(IAsyncResult result)
        {
            //显示线程池现状
            Thread.Sleep(2000);
            PrintMessage("AsyncWriteFile Callback Method");
            //通过result.AsyncState再强制转换为FileStream就能够获取FileStream对象,用于结束异步写入
            FileStream stream = (FileStream)result.AsyncState;
            stream.EndWrite(result);
            stream.Flush();
            stream.Close();
            asyncReadFile();
        }
        #endregion

        // 打印线程池信息
        private static void PrintMessage(String data)
        {
            int workthreadnumber;
            int iothreadnumber;

            // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
            // 获得的可用I/O线程数量给iothreadnumber变量
            ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);

            Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workthreadnumber.ToString(),
                iothreadnumber.ToString());
        }
    }
}
  • 函数原型:public static void GetMinThreads (out int
    workerThreads,out int completionPortThreads)
    参数1:workerThreads:当前由线程池维护的悠闲协助线程的微乎其微数目。 
    参数二:completionPortThreads:当前由线程池维护的悠闲异步 I/O
    线程的细小数目。 

Program

 

 

  叁、Set马克斯Threads()  
 设置能够同时处于活动状态的线程池的最大请求数目(不记挂总结机处理器的数目)

线程池中放入异步操作

    • 函数原型:public static bool SetMinThreads (int
      workerThreads,intcompletionPortThreads)

亚洲必赢官网 18亚洲必赢官网 19

             
 参数一:workerThreads::要由线程池维护的新的小不点儿空闲协助线程数。 
             
 参数二:completionPortThreads::要由线程池维护的新的细微空闲异步 I/O
线程数。 
               重返值:假使改变成功,则为 true;否则为 false。 

using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        private static void AsyncOperation(object state)
        {
            Console.WriteLine("Operation state: {0}", state ?? "(null)");
            Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }

        static void Main(string[] args)
        {
            const int x = 1;
            const int y = 2;
            const string lambdaState = "lambda state 2";

            ThreadPool.QueueUserWorkItem(AsyncOperation);
            Thread.Sleep(TimeSpan.FromSeconds(1));

            ThreadPool.QueueUserWorkItem(AsyncOperation, "async state");
            Thread.Sleep(TimeSpan.FromSeconds(1));

            ThreadPool.QueueUserWorkItem(state => {
                Console.WriteLine("Operation state: {0}", state);
                Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }, "lambda state");

            ThreadPool.QueueUserWorkItem(_ =>
            {
                Console.WriteLine("Operation state: {0}, {1}", x + y, lambdaState);
                Console.WriteLine("Worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }, "lambda state");

            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    }
}

 

Program

  四、SetMinThreads()    
设置线程池在新请求预测中保证的空闲线程数(不思虑总结机处理器的数量)

 

    • 函数原型:public static bool SetMinThreads (int
      workerThreads,intcompletionPortThreads)

线程池同步操作

             
 参数1:workerThreads:要由线程池维护的新的细微空闲协助线程数。 
             
 参数2:completionPortThreads:要由线程池维护的新的小不点儿空闲异步 I/O
线程数。 
               再次回到值:假诺改动成功,则为 true;不然为 false。 

亚洲必赢官网 20亚洲必赢官网 21

  

using System;
using System.Threading;

namespace ConsoleApp1
{
    class ThreadPoolDemo
    {
        static object lockobj = new object();
        static int Count = 0;
        ManualResetEvent manualEvent;
        public ThreadPoolDemo(ManualResetEvent manualEvent)
        {
            this.manualEvent = manualEvent;
        }
        public void DisplayNumber(object a)
        {

            lock (lockobj)
            {
                Count++;
                Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", a, Count, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            }
            //Console.WriteLine("当前运算结果:{0}", a);
            //Console.WriteLine("当前运算结果:{0},当前子线程id:{1} 的状态:{2}", a,Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            //这里是方法执行时间的模拟,如果注释该行代码,就能看出线程池的功能了
            Thread.Sleep(2000);
            //Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", a, Count, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            //这里是释放共享锁,让其他线程进入
            manualEvent.Set();


        }
    }
}

  5、GetAvailableThreads()    获取由 Get马克斯Threads
再次回到的线程池线程的最大数额和如今移动数量之间的差值。    

ThreadPoolDemo

    • 函数原型:public static void GetAvailableThreads (out int
      workerThreads,out int completionPortThreads)

亚洲必赢官网 22亚洲必赢官网 23

                参数一:workerThreads:可用帮忙线程的数据。 
                参数二:completionPortThreads:可用异步 I/O 线程的数额。 

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        //设定任务数量 
        static int count = 10;
        static void Main(string[] args)
        {
            //让线程池执行5个任务所以也为每个任务加上这个对象保持同步
            ManualResetEvent[] events = new ManualResetEvent[count];
            Console.WriteLine("当前主线程id:{0}", Thread.CurrentThread.ManagedThreadId);

            Stopwatch sw = new Stopwatch();
            sw.Start();
            NoThreadPool(count);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);


            sw.Reset();
            sw.Start();
            //循环每个任务
            for (int i = 0; i < count; i++)
            {
                //实例化同步工具
                events[i] = new ManualResetEvent(false);
                //Test在这里就是任务类,将同步工具的引用传入能保证共享区内每次只有一个线程进入
                ThreadPoolDemo tst = new ThreadPoolDemo(events[i]);
                //Thread.Sleep(200);
                //将任务放入线程池中,让线程池中的线程执行该任务                 
                ThreadPool.QueueUserWorkItem(tst.DisplayNumber, i);
            }
            //注意这里,设定WaitAll是为了阻塞调用线程(主线程),让其余线程先执行完毕,
            //其中每个任务完成后调用其set()方法(收到信号),当所有
            //的任务都收到信号后,执行完毕,将控制权再次交回调用线程(这里的主线程)
            ManualResetEvent.WaitAll(events);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);
            //Console.WriteLine("所有任务做完!");
            Console.ReadKey();
        }

        static void NoThreadPool(int count)
        {
            for (int i = 0; i < count; i++)
            {
                Thread.Sleep(2000);
                Console.WriteLine("当前运算结果:{0},Count={1},当前子线程id:{2} 的状态:{3}", i, i + 1, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState);
            }
        }

    }
}

 

Program

  6、QueueUserWorkItem()  
 将艺术排入队列以便执行。此办法在有线程池线程变得可用时实施。 

 

    • 重载方法一:public static bool QueueUserWorkItem (WaitCallback
      callBack)

线程池中的裁撤操作

                重返值:即便将艺术成功排入队列,则为 true;不然为
false。 

亚洲必赢官网 24亚洲必赢官网 25

    • 重载方法二:public static bool QueueUserWorkItem (WaitCallback
      callBack,Object state)
using System;
using System.Threading;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main thread run");
            PrintMessage("Start");
            Run();
            Console.ReadKey();
        }

        private static void Run()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // 这里用Lambda表达式的方式和使用委托的效果一样的,只是用了Lambda后可以少定义一个方法。
            // 这在这里就是让大家明白怎么lambda表达式如何由委托转变的
            ////ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));
            ThreadPool.QueueUserWorkItem(callback, cts.Token);

            Console.WriteLine("Press Enter key to cancel the operation\n");
            Console.ReadLine();

            // 传达取消请求            
            cts.Cancel();
            Console.ReadLine();
        }

        private static void callback(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous Method Start");
            CancellationToken token = (CancellationToken)state;
            Count(token, 1000);
        }

        // 执行的操作,当受到取消请求时停止数数
        private static void Count(CancellationToken token, int countto)
        {
            for (int i = 0; i < countto; i++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Count is canceled");
                    break;
                }

                Console.WriteLine(i);
                Thread.Sleep(300);
            }

            Console.WriteLine("Cout has done");
        }

        // 打印线程池信息
        private static void PrintMessage(String data)
        {
            int workthreadnumber;
            int iothreadnumber;

            // 获得线程池中可用的线程,把获得的可用工作者线程数量赋给workthreadnumber变量
            // 获得的可用I/O线程数量给iothreadnumber变量
            ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);

            Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workthreadnumber.ToString(),
                iothreadnumber.ToString());
        }
    }
}

               参数贰:state :包蕴方法所用数据的靶子。 
               重返值:借使将艺术成功排入队列,则为 true;不然为
false。 
      备注:WaitCallback
回调方法必须与System.Threading.WaitCallback委托项目相匹配。

Program

         WaitCallback函数原型:public delegate void
WaitCallback(Object state);调用QueueUserWorkItem能够经过Object来向任务进度传递参数。假若职分过程必要多少个参数,能够定义包罗那一个数据的类,并将类的实例强制转换为Object数据类型。

 

 

Thread与ThreadPool的2性格质比较

  七、UnsafeQueueUserWorkItem()    非安全性注册多少个等待 WaitHandle
的寄托(将艺术排入队列以便执行)。

亚洲必赢官网 26亚洲必赢官网 27

    • 函数原型:public static bool UnsafeQueueUserWorkItem
      (WaitCallback callBack,Object state)     
      //不将调用堆栈传播到帮助线程上。那允许代码失去调用堆栈,从而升高了它的莱芜特权。
    • 备注:使用
      UnsafeQueueUserWorkItem
      恐怕会无意中打开三个安全漏洞。代码访问安全性的权位检查依据全体调用方对堆栈的权限实行。要是运用
      UnsafeQueueUserWorkItem
      将工作排在有些线程池线程上,则该线程池线程的仓库将不会拥有实际调用方的背景。恶意代码大概会使用这点避开权限检查。
using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            const int numberOfOperations = 300;
            var sw = new Stopwatch();
            sw.Start();
            UseThreads(numberOfOperations);
            sw.Stop();
            Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            UseThreadPool(numberOfOperations);
            sw.Stop();
            Console.WriteLine("Execution time using threadPool: {0}", sw.ElapsedMilliseconds);
        }

        static void UseThreads(int numberOfOperations)
        {
            using (var countdown = new CountdownEvent(numberOfOperations))
            {
                Console.WriteLine("Scheduling work by creating threads");
                for (int i = 0; i < numberOfOperations; i++)
                {
                    var thread = new Thread(() => {
                        Console.Write("{0},", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(TimeSpan.FromSeconds(0.1));
                        countdown.Signal();
                    });
                    thread.Start();
                }
                countdown.Wait();
                Console.WriteLine();
            }
        }

        static void UseThreadPool(int numberOfOperations)
        {
            using (var countdown = new CountdownEvent(numberOfOperations))
            {
                Console.WriteLine("Starting work on a threadpool");
                for (int i = 0; i < numberOfOperations; i++)
                {
                    ThreadPool.QueueUserWorkItem(_ => {
                        Console.Write("{0},", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(TimeSpan.FromSeconds(0.1));
                        countdown.Signal();
                    });
                }
                countdown.Wait();
                Console.WriteLine();
            }
        }
    }
}

 

Program

  8、RegisterWaitForSingleObject()    
将钦定的寄托排队到线程池。当产生以下情形之临时,扶助线程将履行委托。

 

  九、UnsafeRegisterWaitForSingleObject()  
非安全性将点名的委托排队到线程池。

 


 

  线程池示例?

 

  大家先来看二个不难的线程实例:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin in Main");
            Thread t = new Thread(ThreadInvoke);
            t.IsBackground = true;
            t.Start();

            //将当前线程挂起200毫秒
            Thread.Sleep(200);
            Console.WriteLine("End in Main");
            Console.ReadKey();
        }

        static void ThreadInvoke(object obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Execute in ThreadInvoke");
                //每隔100毫秒,循环一次
                Thread.Sleep(100);
            }
        }
    }
}

亚洲必赢官网 28

 

“End in Main”并不曾在ThreadInvoke()方法中存有代码执行完事后才输出。

由此可见Main方法和ThreadInvoke是并行执行的

 

  使用线程池改造上面包车型地铁以身作则:

    上面介绍了只是贰个最简单易行的有关线程线程的例证,但在实际上支出中使用的线程往往是大批量的和越来越复杂的,那时,每回都制造线程、运维线程。从品质上来讲,那样做并不出彩(因为每使用2个线程就要创造二个,须要占用系统开发);从操作上来讲,每一遍都要开动,比较费心。为此引入的线程池的概念。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin in Main");
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadInvoke));
            Console.WriteLine("End in Main");
            //将当前线程挂起200毫秒
            Thread.Sleep(3000);

            Console.ReadKey();
        }

        static void ThreadInvoke(object obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Execute in ThreadInvoke");
                //每隔100毫秒,循环一次
                Thread.Sleep(100);
            }
        }
    }
}

 

Thread.Sleep(三千)那句话是必须的因为当Main方法甘休后,.Net环境会活动终止销毁线程池,为了确定保障做到线程池里的职务,所以主线程必要静观其变1段时间。 

由输出结果可见,Main方法和ThreadInvoke方法是并行执行的。

 

网站地图xml地图