威尼斯人线上娱乐

【威尼斯人线上娱乐】线程从素不相识到熟稔,线程池的利用

2 4月 , 2019  

CLXC90线程池并不会在CL帕杰罗开头化时立时成立线程,而是在应用程序要创设线程来运作职责时,线程池才开首化1个线程。
线程池开端化时是从未有过线程的,线程池里的线程的开始化与其余线程一样,然则在成功任务之后,该线程不会活动销毁,而是以挂起的景况重临到线程池。直到应用程序再次向线程池发出请求时,线程池里挂起的线程就会重复激活执行职务。
这么既节约了创设线程所导致的品质损耗,也足以让五个义务反复重用同一线程,从而在应用程序生存期内节约多量费用。

后日我们来谈谈线程池:

  为啥使用线程池?  

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

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

威尼斯人线上娱乐 1

 从此图中大家会意识 .NET 与C#
的各个版本发表都是有2个“核心”。即:C#壹.0托管代码→C#2.0泛型→C#3.0LINQ→C#肆.0动态语言→C#伍.0异步编制程序。今后自个儿为新型版本的“异步编制程序”主旨写连串分享,期待您的查看及点评。

 

前几天的应用程序越来越复杂,大家平日须求运用《异步编制程序:线程概述及应用》中涉嫌的多线程技术来提升应用程序的响应速度。那时大家往往的成立和销毁线程来让应用程序急迅响应操作,那往往的开创和销毁无疑会减低应用程序品质,大家能够引入缓存机制消除这些题材,此缓存机制亟待消除如:缓存的高低难点、排队执行职分、调度空闲线程、按需成立新线程及销毁多余空闲线程……最近微软已经为大家提供了现成的缓存机制:线程池

        
线程池原自于对象池,在详细分解明线程池前让大家先来打探下何为对象池。

流程图:

 威尼斯人线上娱乐 2

 

         对于对象池的清理平日设计三种办法:

1)         手动清理,即积极调用清理的不二秘籍。

2)         自动清理,即由此System.Threading.Timer来完结定时清理。

 

第二达成代码:

 

  威尼斯人线上娱乐 3public
sealed class ObjectPool<T> where T : ICacheObjectProxy<T> {
// 最大容积 private Int32 m_maxPoolCount = 30; // 最小体积 private
Int3贰 m_minPoolCount = 5; // 已存体积 private Int3贰 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, Int3二 minPoolCount, Object[]
create_params){ } /// <summary> /// 获取三个对象实例 ///
</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静态类,为应用程序提供一个由系统一管理理的帮助线程池,从而使您能够集中精力于应用程序任务而不是线程管理。种种进度都有三个线程池,1个Process中只好有多个实例,它在挨家挨户应用程序域(AppDomain)是共享的。

在里面,线程池将协调的线程划分工小编线程(帮忙线程)和I/O线程。前者用于实践常常的操作,后者专用于异步IO,比如文件和互连网请求,注意,分类并不表明两种线程自己有差距,内部依旧是均等的。

威尼斯人线上娱乐 4public
static class ThreadPool { //
将操作系统句柄绑定到System.Threading.ThreadPool。 public static bool
BindHandle(SafeHandle osHandle); //
检索由ThreadPool.Get马克斯Threads(Int3贰,Int32)方法重返的最大线程池线程数和眼下活动线程数之间的差值。
public static void GetAvailableThreads(out int workerThreads , out int
completionPortThreads); //
设置和摸索能够同时处于活动状态的线程池请求的多少。 //
全部大于此数据的伸手将保持排队状态,直到线程池线程变为可用。 public
static bool SetMaxThreads(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的委托,并点名一个 33人有号子整数来代表超时值(以阿秒为单位)。 // executeOnlyOnce如若为
true,表示在调用了委托后,线程将不再在waitObject参数上等待; // 借使为
false,表示每便实现等待操作后都重置计时器,直到撤消等待。 public static
RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject
, WaitOrTimerCallback callBack, object state, Int
millisecondsTimeOutInterval, bool executeOnlyOnce); public static
RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle
waitObject , WaitOr提姆erCallback callBack , object state , int
millisecondsTimeOutInterval , bool executeOnlyOnce); …… } ThreadPool

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

可排队到线程池的操作数仅受内部存款和储蓄器的范围;而线程池限制进度中能够而且处于活动状态的线程数(暗中同意意况下,限制各个CPU 能够行使 二伍 个工作者线程和 一,000 个 I/O 线程(根据机器CPU个数和.net
framework版本的不如,那几个多少大概会有转移)),全体大于此数据的伸手将保险排队状态,直到线程池线程变为可用。

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

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

b)        
其实FileStream的异步读写,异步发送接受Web请求,System.Threading.Timer定时器,甚至运用delegate的beginInvoke都会暗中认可调用
ThreadPool,也正是说不仅你的代码大概选用到线程池,框架之中也说不定接纳到。

c)        
一个施用程序池是二个独立的经过,拥有1个线程池,应用程序池中得以有多少个WebApplication,各样运营在一个独门的AppDomain中,这几个WebApplication公用一个线程池。

 

二)         使用GetMinThreads()和SetMinThreads()获取和设置最小空闲线程数

为幸免向线程分配不须要的库房空间,线程池遵照一定的时辰间隔创立新的悠闲线程(该距离为半秒)。所以壹旦最小空闲线程数设置的过小,在长期内执行大气任务会因为制造新空闲线程的松开延迟导致质量瓶颈。最小空闲线程数私下认可值等于机械上的CPU核数,并且不建议改变最小空闲线程数。

在运行线程池时,线程池具有3个平放延迟,用于启用最小空闲线程数,以增强应用程序的吞吐量。

在线程池运营中,对于推行完义务的线程池线程,不会及时销毁,而是再次回到到线程池,线程池会维护最小的空闲线程数(固然应用程序全部线程都以悠闲状态),以便队列职务能够及时运转。超越此最小数目标悠闲线程一段时间没事做后会自身醒来终止自个儿,以节省系统财富。

三)         静态方法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
都会捕获调用方的仓库,此堆栈将在线程池线程开头实践任务时合并到线程池线程的库房中。假诺必要展开安检,则必须检查整个堆栈,但它还具有一定的性质费用。使用“不安全的”方法调用并不会提供绝对的鄂州,但它会提供更好的特性。

让三个线程不分明地伺机三个根本对象进入可用状态,那对线程的内部存款和储蓄器能源来说是一种浪费。ThreadPool.RegisterWaitForSingleObject()为大家提供了一种方法:在三个基石对象变得可用的时候调用3个艺术。

运用需注意:

一)         WaitOr提姆erCallback委托参数,该信托接受一个名字为timeOut的Boolean参数。如若 WaitHandle 在内定时间内未有收受功率信号(即,超时),则为true,不然为 false。回调方法能够依照timeOut的值来针对地选择措施。

二)         名字为executeOnlyOnce的Boolean参数。传true则代表线程池线程只举行回调方法叁次;若传false则意味着内核查象每一遍收到非确定性信号,线程池线程都会进行回调方法。等待1个AutoReset伊夫nt对象时,那些效应越来越有用。

叁)         RegisterWaitForSingleObject()方法再次回到3个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); AutoReset伊夫nt
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, TimeSpan.FromSeconds(二), true ); //
撤销等待操作(即不再执行WaitOrTimerCallback委托)
registeredWaitHandle.Unregister(notificWaitHandle); // 公告ThreadPool.RegisterWaitForSingleObject( notificWaitHandle, (Object
state, bool timedOut) => { if (timedOut)
Console.WriteLine(“第1个RegisterWaitForSingleObject未有调用Unregister()”);
else
Console.WriteLine(“第2个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()方法)。

当贰个“时间片”截至时,假使Windows决定再一次调度同1个线程,那么Windows不会实施上下文切换。要是Windows调度了3个不如的线程,这时Windows执行线程上下文切换。

        
当Windows上下文切换成另1个线程时,CPU将推行多少个例外的线程,而从前线程的代码和数码还在CPU的高速缓存中,(高速缓存使CPU不必平时访问RAM,RAM的进程比CPU高速缓存慢得多),当Windows上下文切换成一个新线程时,那一个新线程极有相当大只怕要实施差异的代码并走访分裂的多少,这么些代码和数码不在CPU的高速缓存中。由此,CPU必须访问RAM来填充它的高速缓存,以回复不慢实汇兑况。不过,在其“时间片”执行完后,二次新的线程上下文切换又生出了。

上下文切换所发生的支付不会换成任何内存和总体性上的入账。执行上下文所需的时刻取决于CPU架构和速度(即“时间片”的分红)。而填充CPU缓存所需的日子取决于系统运维的应用程序、CPU、缓存的分寸以及别的种种因素。所以,不可能为每叁次线程上下文切换的年华支付给出一个规定的值,甚至不知所厝提交三个估价的值。唯一明确的是,尽管要塑造高品质的应用程序和组件,就应有尽恐怕幸免线程上下文切换。

除了,执行垃圾回收时,CLRubicon必须挂起(暂停)全数线程,遍历它们的栈来查找根以便对堆中的对象进行标记,再度遍历它们的栈(有的对象在回落时期发生了运动,所以要翻新它们的根),再过来全部线程。所以,裁减线程的数据也会鲜明提高垃圾回收器的属性。每一遍使用三个调试器并境遇一个断点,Windows都会挂起正在调试的应用程序中的全数线程,并在单步执行或运营应用程序时上升所有线程。因而,你用的线程越来越多,调节和测试体验也就越差。

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

威尼斯人线上娱乐 6

在《异步编制程序:线程概述及接纳》中作者关系了Thread的八个上下文,即:

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

2)         ExecutionContext   
获取二个System.Threading.ExecutionContext对象,该对象涵盖关于当前线程的各类上下文的音信。首要用于线程间数据共享。

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

威尼斯人线上娱乐 7public
sealed class ExecutionContext : IDisposable, I塞里alizable { public void
Dispose(); public void GetObjectData(SerializationInfo info,
StreamingContext context); //
此办法对于将实施上下文从三个线程传播到另贰个线程万分实惠。 public
ExecutionContext CreateCopy(); // 从如今线程捕获执行上下文的一个副本。
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
类提供的法力让用户代码能够在用户定义的异步点之间捕获和传导此上下文。公共语言运营时(CLLacrosse)确认保障在托管进程内运转时定义的异步点之间平等地传输
ExecutionContext。

每当三个线程(开头线程)使用另多个线程(辅助线程)执行任务时,CLRAV四会将前者的施行上下文流向(复制到)援助线程(注意那么些活动流向是单方向的)。那就保险了帮忙线程执行的任何操作使用的是均等的安全设置和宿主设置。还保险了初步线程的逻辑调用上下文能够在支持线程中央银行使。

但施行上下文的复制会造成一定的属性影响。因为执行上下文中包蕴大批量音讯,而采访全数那么些音信,再把它们复制到协助线程,要费用多如牛毛岁月。即使补助线程又采纳了越多地扶持线程,还必须创立和开始化越多的实践上下文数据结构。

故此,为了升高应用程序质量,大家得以阻挡实施上下文的流动。当然那唯有在帮扶线程不必要依然不访问上下文消息的时候才能举行阻拦。

上边给出3个演示为了演示:

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

二)         为了升高品质,阻止\复原执行上下文的流淌。

3)         在时下线程上的内定执行上下文中运维有个别方法。

威尼斯人线上娱乐 8private
static void Example_ExecutionContext() {
CallContext.LogicalSetData(“Name”, “小红”);
Console.WriteLine(“主线程中Name为:{0}”,
CallContext.LogicalGetData(“Name”)); // 一)
在线程间共享逻辑调用上下文数据(CallContext)。
Console.WriteLine(“1)在线程间共享逻辑调用上下文数据(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())的上下文”。

二)        
撤消执行上下文流动除了使用ExecutionContext.SuppressFlow()情势外。还是能经过应用ThreadPool的UnsafeQueueUserWorkItem

UnsafeRegisterWaitForSingleObject来执行委托方法。原因是不安全的线程池操作不会传导压缩堆栈。每当压缩堆栈流动时,托管的大旨、同步、区域安装和用户上下文也随后流动。

 

线程池线程中的非凡

线程池线程中未处理的那一个将告1段落进程。以下为此规则的两种例外意况: 

  1. 出于调用了 Abort,线程池线程中校引发ThreadAbortException。 
    二.
    出彭三源值卸载应用程序域,线程池线程少校引发AppDomainUnloadedException。 
  2. 集体语言运转库或宿主进度将终止线程。

哪一天不使用线程池线程

今日天津大学学家都早就知道线程池为大家提供了便利的异步API及托管的线程管理。那么是否别的时候都应当使用线程池线程呢?当然不是,大家如故须要“因地制宜”的,在偏下两种处境下,适合于创设并管理本人的线程而不是使用线程池线程:

 

 

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

线程池尽管为大家提供了异步操作的有利,不过它不支持对线程池中单个线程的扑朔迷离控制致使我们有些情形下会一贯动用Thread。并且它对“等待”操作、“撤消”操作、“连续”任务等操作比较繁琐,或者驱使你从新造轮子。微软也想开了,所以在.NET四.0的时候投入了“并行义务”并在.NET四.第55中学对其展开改善,想询问“并行任务”的园友能够先看看《(译)关于Async与Await的FAQ》。

本节到此结束,多谢大家的观赏。赞的话还请多引进啊 (*^_^*)

 

 

 

 

参考资料:《CLKuga via C#(第三版)》

 

 摘自:

 

异步编程:使用线程池管理线程 从此图中我们会发觉 .NET 与C#
的每一个版本公布皆以有2个主旨…

通过CLEscort线程池所建立的线程总是暗中同意为后台线程,优先级数为ThreadPriority.Normal。

应用程序能够有多个线程,那么些线程在蛰伏状态中需求花费大批量年华来等待事件发生。其余线程大概进入睡眠状态,并且仅定期被唤起以轮循更改或更新情状消息,然后再度进入休眠状态。为了简化对那么些线程的管理,.NET框架为每一种进程提供了3个线程池,1个线程池有多少个等待操作情形,当一个守候操作完成时,线程池中的支持线程会执行回调函数。线程池中的线程由系统一管理理,程序员不须求费劲于线程管理,能够集中精力处理应用程序职分。通过基础类库中的ThreadPool类提供二个线程池,该线程池可用以发送工作现,处理异步I/O,代表任何线程等待及处理计时器.ThreadPool类的具备办法都以静态方法.ThreadPool自身也是三个静态类.
我们来探望她的定义和局部常用的秘籍:
 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:包括方法所用数据的对象。
下边看个例证:

  在面向对象编制程序中,成立和销毁对象是很费时间的,因为成立多少个对象要博取内部存款和储蓄器财富照旧其余越多能源,所以加强服务程序作用的二个手腕正是尽也许收缩创制和销毁对象的次数,尤其是有的很耗电源的对象创制和销毁。怎么样使用已有对象来服务正是3个亟待缓解的关键难题,其实那正是一些”池化能源”技术发生的原故。比如大家所熟稔的数据库连接池正是服从那1钻探而发出的,本文将介绍的线程池技术一样符合那1构思。

CL中华V线程池分为劳力线程(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奥德赛内部对象的运行,常常用于总括密集的天职。
  • I/O(Input/Output)线程注重用以与外部系统相互音信,如输入输出,CPU仅需在任务开首的时候,将职责的参数字传送递给配备,然后运行硬件配备即可。等职分完结的时候,CPU收到四个公告,壹般的话是三个硬件的暂停能量信号,此时CPU继续后继的拍卖工作。在处理进度中,CPU是不用完全加入处理进程的,假诺正在周转的线程不交出CPU的控制权,那么线程也只可以处于等候状态,固然操作系统将如今的CPU调度给别的线程,此时线程所占有的半空中仍旧被占用,而并不曾CPU处理那一个线程,也许出现线程能源浪费的难点。借使那是多少个网络服务程序,每二个互联网连接都选取贰个线程管理,或许出现大批量线程都在伺机互联网通信,随着网络连接的四处追加,处于等候情形的线程将会很费用尽全体的内部存款和储蓄器能源。能够想念使用线程池化解这一个标题。

 

  十2线程是怎样?组成?特点?

  线程池的最大值一般默许为一千、3000。当不止此数据的央求时,将保证排队情形,直到线程池里有线程可用。

 运营的结果为

  线程池是一种四线程处理格局,处理进度准将职分添加到行列,然后在开立线程后活动运营这个职分。线程池中的线程由系统一管理理,程序员不需求费力于线程管理,能够集中精力处理应用程序任务。

  使用CLXC60线程池的劳引力线程一般有三种办法:

威尼斯人线上娱乐 10

  组成:服务器程序利用线程技术响应客户请求已经无独有偶,恐怕您觉得这么做成效已经很高,但你有未有想过优化一下行使线程的方法。该小说将向你介绍服务器程序怎样利用线程池来优化品质并提供多个粗略的线程池完毕。

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

那里有个类为AutoReset伊夫nt,他的功效是通报正在守候的线程已发出事变。他是从伊夫ntWaitHandle继承而来的!例子中分头用了三种分化的法子调用,第三种是足以传递参数的!工作线程壹就传递了”小编的参数”字符串!工作线程二运营完了会打招呼等待的线程已发出事件.那里AutoReset伊夫nt早先化的时候首先将连续信号设成false,工作线程贰一旦调用成功,将被设成true. asyncOpIsDone.WaitOne()阻塞当前线程,直到收到时限信号!

  1、线程池管理器(ThreadPoolManager):用于创设并管理线程池

  要留意,不论是透过ThreadPool.QueueUserWorkItem()仍旧委托,调用的都以线程池里的线程。

再看上面包车型大巴事例

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

因而以下八个格局能够读取和安装CL牧马人线程池中工小编线程与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 设置线程池最少需要保留的线程数

 

  特点:

大家得以使用线程池来缓解地点的大部难点,跟使用单个线程相比较,使用线程池有如下优点:

运作结果为

  • 多个经过有且只有二个线程池。
  • 线程池线程都今后台线程(即不会阻止进程的停下)
  • 各种线程都选拔暗中认可堆栈大小,以暗中同意的先行级运营,并处于三十二线程单元中。当先最大值的别的线程需求排队,但它们要等到其余线程实现后才开动。
  • 在CL福睿斯 二.0 SP一从前的版本中,线程池中 暗中认可最大的线程数量 = 处理器数 *
    二5, CLLX570 2.0 SP一之后就成为了 私下认可最大线程数量 = 处理器数 *
    250,线程上限可以变更,通过运用ThreadPool.Get马克斯+Threads和ThreadPool.Set马克斯Threads方法,能够获取和设置线程池的最大线程数。
  • 暗许情况下,种种处理器维持3个悠闲线程,即默许最小线程数 =
    处理器数。
  • 当进程运维时,线程池并不会活动创设。当第一次将回调方法排入队列(比如调用ThreadPool.QueueUserWorkItem方法)时才会创造线程池。
  • 在对多个工作项实行排队之后将不可能收回它。
  • 线程池中线程在成功任务后并不会自行销毁,它会以挂起的气象再次来到线程池,要是应用程序再度向线程池发出请求,那么那些挂起的线程将激活并推行职分,而不会创建新线程,那将节省了过多付出。唯有线程达到最大线程数量,系统才会以一定的算法销毁回收线程。

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

 


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

威尼斯人线上娱乐 11

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

三、线程池会依照当下系统特性对池内的线程进行优化处理。

本例中能够详细看AutoRest伊夫nt的用法MyWork一实际先甘休的,不过asyncOpIsDone须求等MyWork的时限信号!所以先输出了MyWork结束.那里还有三个东西小编想说的正是WaitHandle,上边包车型地铁事例已经提交了他的用法!他是AutoRsetEvent的基类.

  一、要求大批量的线程来成功任务,且做到职责的时间相比短。
WEB服务器完结网页请求那样的职分,使用线程池技术是这个适宜的。因为单个任务小,而职务数量巨大,你能够想像三个热点网址的点击次数。
但对于长日子的职责,比如一个Telnet连接请求,线程池的长处就不备受瞩目了。因为Telnet会话时间比线程的创始时间大概了。

总的说来使用线程池的功用就是压缩创立和销毁线程的系统开发。在.NET中有三个线程的类ThreadPool,它提供了线程池的保管。

再有ThreadPool有1个函数RegisterWaitForSingleObject这几个函数依旧满有意思的!小编这里就不再给出例子了!

  2、对质量要求苛刻的行使,比如供给服务器神速响应客户请求。

ThreadPool是贰个静态类,它从未构造函数,对外提供的函数也整整是静态的。在这之中有3个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();
        }
    }
}

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

Program

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

 

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

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

 

威尼斯人线上娱乐 16威尼斯人线上娱乐 17

  二、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)
    参数壹: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)

线程池同步操作

             
 参数壹:workerThreads:要由线程池维护的新的微乎其微空闲帮忙线程数。 
             
 参数二: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();


        }
    }
}

  伍、GetAvailableThreads()    获取由 Get马克斯Threads
重回的线程池线程的最大数额和脚下移动数量之间的差值。    

ThreadPoolDemo

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

威尼斯人线上娱乐 22威尼斯人线上娱乐 23

                参数1: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

  陆、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的贰个属性比较

  七、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地图