【4858.com】线程池的使用,使用线程池管理线程

By admin in 4858.com on 2019年3月15日

CL福睿斯线程池并不会在CL揽胜早先化时即时创设线程,而是在应用程序要开创线程来运行职分时,线程池才起头化三个线程。
线程池初步化时是从未线程的,线程池里的线程的开首化与任何线程一样,不过在做到职务之后,该线程不会自行销毁,而是以挂起的情况重回到线程池。直到应用程序再度向线程池发出请求时,线程池里挂起的线程就会再度激活执行任务。
那样既节省了建立线程所造成的属性损耗,也得以让七个职分反复重用同一线程,从而在应用程序生存期内节约大量开发。

前天我们来谈谈线程池:

  干什么使用线程池?  

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

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

4858.com 1

 从此图中大家会发现 .NET 与C#
的各类版本公布都以有一个“主旨”。即:C#1.0托管代码→C#2.0泛型→C#3.0LINQ→C#4.0动态语言→C#5.0异步编制程序。今后作者为流行版本的“异步编制程序”大旨写系列分享,期待你的查阅及点评。

 

【4858.com】线程池的使用,使用线程池管理线程。最近的应用程序越来越复杂,大家平日须要选取《异步编程:线程概述及使用》中关系的二十多线程技术来增强应用程序的响应速度。那时咱们反复的创办和销毁线程来让应用程序连忙响应操作,那往往的成立和销毁无疑会下落应用程序质量,我们得以引入缓存机制化解那个标题,此缓存机制亟待消除如:缓存的轻重难题、排队执行职分、调度空闲线程、按需成立新线程及销毁多余空闲线程……近期微软一度为大家提供了现成的缓存机制:线程池

        
线程池原自于对象池,在事无巨细表达明线程池前让大家先来打听下何为对象池。

流程图:

 4858.com 2

 

         对于对象池的清理平常设计三种方法:

1)         手动清理,即积极调用清理的办法。

2)         自动清理,即透过System.Threading.Timer来达成定时清理。

 

最首要完结代码:

 

  4858.com 3public
sealed class ObjectPool<T> where T : ICacheObjectProxy<T> {
// 最大容积 private Int32 m_maxPoolCount = 30; // 最小容积 private
Int32 m_minPoolCount = 5; // 已存容积 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(Int32 maxPoolCount, Int32 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){ } }
完成的首要代码

 

因而对“对象池”的1个大体会认识识能帮大家更快通晓线程池。

 

线程池ThreadPool类详解

ThreadPool静态类,为应用程序提供三个由系统一管理理的协助线程池,从而使你能够集中精力于应用程序职责而不是线程管理。种种过程都有贰个线程池,四个Process中只好有三个实例,它在逐一应用程序域(AppDomain)是共享的。

在中间,线程池将协调的线程划分工作者线程(帮忙线程)和I/O线程。前者用于实践日常的操作,后者专用于异步IO,比如文件和互连网请求,注意,分类并不表明二种线程本人有距离,内部依然是均等的。

4858.com 4public
static class ThreadPool { //
将操作系统句柄绑定到System.Threading.ThreadPool。 public static bool
BindHandle(SafeHandle osHandle); //
检索由ThreadPool.Get马克斯Threads(Int32,Int32)方法重返的最大线程池线程数和当前活动线程数之间的差值。
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的寄托,并钦定二个 3四人有记号整数来表示超时值(以微秒为单位)。 // 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
millisecondsTimeOutInterval , bool executeOnlyOnce); …… } ThreadPool

1)         使用Get马克斯Threads()和SetMaxThreads()获取和安装最大线程数

可排队到线程池的操作数仅受内部存款和储蓄器的限定;而线程池限制进度中得以同时处于活动状态的线程数(暗中认可意况下,限制每种CPU 能够应用 25 个工小编线程和 1,000 个 I/O 线程(依据机器CPU个数和.net
framework版本的不比,这几个数量恐怕会有转移)),全体大于此数额的呼吁将保险排队状态,直到线程池线程变为可用。

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

a)        
将线程池大小设置得太大,大概会造成更频仍的履行上下文切换及深化能源的争用情状。

b)        
其实FileStream的异步读写,异步发送接受Web请求,System.Threading.提姆er定时器,甚至动用delegate的beginInvoke都会暗中同意调用
ThreadPool,也正是说不仅你的代码大概使用到线程池,框架之中也可能应用到。

c)        
一个使用程序池是一个独自的进程,拥有八个线程池,应用程序池中能够有多少个WebApplication,每种运转在3个独立的AppDomain中,那么些WebApplication公用一个线程池。

 

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

为制止向线程分配不要求的仓库空间,线程池按照一定的年月距离创造新的闲暇线程(该区间为半秒)。所以只要最小空闲线程数设置的过小,在长时间内执行大气任务会因为制造新空闲线程的放置延迟导致品质瓶颈。最小空闲线程数暗中认可值等于机械上的CPU核数,并且不提出改变最小空闲线程数。

在起步线程池时,线程池具有3个放置延迟,用于启用最小空闲线程数,以狠抓应用程序的吞吐量。

在线程池运维中,对于实施完职责的线程池线程,不会立马销毁,而是重返到线程池,线程池会维护最小的空闲线程数(尽管应用程序全数线程都以悠闲状态),以便队列职分能够霎时运转。超过此最小数指标空余线程一段时间没事做后会自身醒来终止自身,以节省系统财富。

3)         静态方法GetAvailableThreads()

通过静态方法GetAvailableThreads()再次来到的线程池线程的最大数目和当前移动数量之间的差值,即获取线程池中当前可用的线程数目

4)         七个参数

格局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
都会捕获调用方的仓库,此堆栈将在线程池线程发轫履行任务时合并到线程池线程的库房中。若是必要展开安检,则必须检查整个堆栈,但它还富有自然的属性开销。使用“不安全的”方法调用并不会提供相对的乌海,但它会提供更好的性质。

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

行使需注意:

1)         WaitOr提姆erCallback委托参数,该信托接受1个名为timeOut的Boolean参数。要是 WaitHandle 在钦点时间内尚未吸收信号(即,超时),则为true,不然为 false。回调方法能够遵照timeOut的值来针对地选取措施。

2)         名为executeOnlyOnce的Boolean参数。传true则意味线程池线程只进行回调方法3遍;若传false则象征内核查象每一遍收到信号,线程池线程都会实施回调方法。等待六个AutoReset伊芙nt对象时,那几个意义尤为有用。

3)         RegisterWaitForSingleObject()方法重临三个RegisteredWaitHandle对象的引用。这么些目的标识了线程池正在它上边等待的基本对象。我们得以调用它的Unregister(WaitHandle
waitObject)方法废除由RegisterWaitForSingleObject()注册的等候操作(即WaitOrTimerCallback委托不再实施)。Unregister(WaitHandle
waitObject)的WaitHandle参数表示成功撤消注册的等候操作后线程池会向此目的发出信号(set()),若不想接收此通告能够传递null。

         示例:

4858.com 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(2), true ); //
撤废等待操作(即不再进行WaitOrTimerCallback委托)
registeredWaitHandle.Unregister(notificWaitHandle); // 布告ThreadPool.RegisterWaitForSingleObject( notificWaitHandle, (Object
state, bool timedOut) => { if (timedOut)
Console.WriteLine(“第二个RegisterWaitForSingleObject没有调用Unregister()”);
else
Console.WriteLine(“第3个RegisterWaitForSingleObject调用了Unregister()”);
endWaitHandle.Set(); }, null, TimeSpan.FromSeconds(4), true );
endWaitHandle.WaitOne(); } 示例

实施上下文

        
上一小节中说到:线程池最大线程数设置过大或然会招致Windows频仍执行上下文切换,下跌程序质量。对于绝当先5/10园友不会壮志未酬这样的答疑,作者和你同样也喜欢“知其然,再知其所以然”。

.NET中上下文太多,我最终得出的结论是:上下文切换中的上下文专指“执行上下文”。

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

当1个“时间片”截至时,若是Windows决定再度调度同三个线程,那么Windows不会履行上下文切换。假使Windows调度了3个不等的线程,那时Windows执行线程上下文切换。

        
当Windows上下文切换成另一个线程时,CPU将推行二个两样的线程,而以前线程的代码和数码还在CPU的高速缓存中,(高速缓存使CPU不必常常访问RAM,RAM的速度比CPU高速缓存慢得多),当Windows上下文切换到一个新线程时,这些新线程极有恐怕要实践不一的代码并走访差别的数据,这么些代码和数码不在CPU的高速缓存中。由此,CPU必须访问RAM来填充它的高速缓存,以平复非常的慢实市价况。不过,在其“时间片”执行完后,三回新的线程上下文切换又发出了。

上下文切换所产生的开发不会换到任何内部存款和储蓄器和天性上的收益。执行上下文所需的小时取决于CPU架构和速度(即“时间片”的分红)。而填充CPU缓存所需的时刻取决于系统运作的应用程序、CPU、缓存的深浅以及此外各个因素。所以,不恐怕为每1回线程上下文切换的光阴支付给出3个规定的值,甚至无所适从提交3个估计的值。唯一分明的是,若是要营造高质量的应用程序和零部件,就应该尽大概防止线程上下文切换。

除了,执行垃圾回收时,CL瑞鹰必须挂起(暂停)所无线程,遍历它们的栈来查找根以便对堆中的对象实行标记,再一次遍历它们的栈(有的对象在回落时期发生了移动,所以要翻新它们的根),再回复全部线程。所以,收缩线程的数据也会分明提高垃圾回收器的个性。每一回使用2个调节和测试器并遭遇多个断点,Windows都会挂起正在调节和测试的应用程序中的所无线程,并在单步执行或运维应用程序时上涨全体线程。由此,你用的线程越来越多,调节和测试体验也就越差。

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

4858.com 6

在《异步编制程序:线程概述及使用》中本人关系了Thread的多少个上下文,即:

1)         CurrentContext       
获取线程正在里面实行的方今上下文。重要用来线程内部存款和储蓄数据。

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

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

4858.com 7public
sealed class ExecutionContext : IDisposable, ISerializable { public void
Dispose(); public void GetObjectData(SerializationInfo info,
StreamingContext context); //
此办法对于将执行上下文从3个线程传播到另一个线程万分有效。 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
类提供的效能让用户代码能够在用户定义的异步点之间捕获和传导此上下文。公共语言运维时(CLLX570)确认保证在托管过程内运营时定义的异步点之间平等地传输
ExecutionContext。

每当多少个线程(开首线程)使用另三个线程(协助线程)执行义务时,CL奥迪Q5会将前者的实践上下文流向(复制到)帮助线程(注意这几个活动流向是单方向的)。这就有限扶助了救助线程执行的其它操作使用的是平等的中卫设置和宿主设置。还打包票了初步线程的逻辑调用上下文能够在赞助线程中利用。

但推行上下文的复制会导致一定的习性影响。因为实施上下文中包括大量消息,而采访全数这一个新闻,再把它们复制到帮衬线程,要消耗不可胜举时辰。假设扶助线程又采纳了更加多地支持线程,还非得创设和早先化越来越多的执行上下文数据结构。

由此,为了升高应用程序质量,大家能够阻止实施上下文的流淌。当然那唯有在赞助线程不要求或许不访问上下文音讯的时候才能拓展拦截。

上边给出1个示范为了演示:

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

2)         为了进步品质,阻止\还原执行上下文的流动。

3)         在时下线程上的钦赐执行上下文中运作有个别方法。

4858.com 8private
static void Example_ExecutionContext() {
CallContext.LogicalSetData(“Name”, “小红”);
Console.WriteLine(“主线程中Name为:{0}”,
CallContext.LogicalGetData(“Name”)); // 1)
在线程间共享逻辑调用上下文数据(CallContext)。
Console.WriteLine(“1)在线程间共享逻辑调用上下文数据(CallContext)。”);
ThreadPool.QueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程中Name为:\”{0}\””,
CallContext.LogicalGetData(“Name”))); Thread.Sleep(500);
Console.WriteLine(); // 2) 为了提高质量,打消\复原执行上下文的流动。
ThreadPool.UnsafeQueueUserWorkItem((Object obj) =>
Console.WriteLine(“ThreadPool线程使用Unsafe异步执行情势来撤销执行上下文的流动。Name为:\”{0}\””
, CallContext.LogicalGetData(“Name”)), null);
Console.WriteLine(“2)为了进步品质,撤消/复苏执行上下文的流动。”);
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(); // 3)
在眼下线程上的内定执行上下文中运维有些方法。(通过获取调用上下文数据他们表明)
Console.WriteLine(“3)在脚下线程上的钦定执行上下文中运作某些方法。(通过获取调用上下文数据印证)”);
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

结果如图:

4858.com 9

 

 

 注意:

1)        
示例中“在日前线程上的钦赐执行上下文中运转有些方法”:代码中必须使用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的时候参加了“并行职务”并在.NET4.5中对其开始展览革新,想询问“并行职务”的园友能够先看看《(译)关于Async与Await的FAQ》。

本节到此截至,谢谢我们的欣赏。赞的话还请多引进啊 (*^_^*)

 

 

 

 

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

 

 摘自:

 

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

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

应用程序能够有五个线程,那几个线程在蛰伏状态中须要开销大量岁月来等待事件产生。别的线程或许进入睡眠状态,并且仅定期被唤醒以轮循更改或更新处境新闻,然后再度进入休眠状态。为了简化对这么些线程的管理,.NET框架为各类进程提供了八个线程池,一个线程池有多少个等待操作意况,当二个等候操作达成时,线程池中的帮衬线程会执行回调函数。线程池中的线程由系统管理,程序员不需求费劲于线程管理,能够集中精力处理应用程序任务。通过基础类库中的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:包涵方法所用数据的靶子。
上面看个例子:

  在面向对象编制程序中,创立和销毁对象是很费时间的,因为创建1个对象要拿走内部存款和储蓄器能源依旧别的越多财富,所以狠抓服务程序效能的1个一手正是尽恐怕减弱成立和销毁对象的次数,尤其是部分很耗电源的对象成立和销毁。如何行使已有指标来服务正是三个亟需化解的关键难题,其实那正是有的”池化能源”技术产生的案由。比如我们所熟稔的数据库连接池便是遵从这一盘算而发生的,本文将介绍的线程池技术一样符合这一合计。

CLMurano线程池分为劳力线程(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 }

  • 劳力线程是至关心爱护要用作管理CLEvoque内部对象的运转,平常用于计算密集的任务。
  • I/O(Input/Output)线程主要用于与表面系统相互新闻,如输入输出,CPU仅需在义务初步的时候,将职务的参数字传送递给装备,然后运行硬件设备即可。等职分完成的时候,CPU收到3个公告,一般的话是一个硬件的刹车信号,此时CPU继续后继的拍卖工作。在处理进度中,CPU是不用完全参预处理进度的,要是正在运维的线程不交出CPU的控制权,那么线程也只可以处于等候状态,即便操作系统将近日的CPU调度给其余线程,此时线程所占用的长空仍然被占用,而并从未CPU处理这些线程,或然现身线程能源浪费的标题。即便那是1个网络服务程序,每五个互连网连接都利用叁个线程管理,恐怕出现大批量线程都在等候互联网通讯,随着网络连接的持续充实,处于等候状态的线程将会很开支尽全部的内部存款和储蓄器能源。能够设想使用线程池解决这些题材。

 

  多线程是何等?组成?特点?

  线程池的最大值一般私下认可为一千、3000。当不止此数额的请求时,将有限援助排队状态,直到线程池里无线程可用。

 运行的结果为

  线程池是一种三十二线程处理形式,处理进程团长职责添加到行列,然后在开立线程后活动运营这一个任务。线程池中的线程由系统管理,程序员不须要费劲于线程管理,能够集中精力处理应用程序职务。

  使用CL普拉多线程池的劳引力线程一般有二种格局:

4858.com 10

  组成:服务器程序利用线程技术响应客户请求已经司空见惯,或然你认为这么做成效已经很高,但您有没有想过优化一下利用线程的情势。该小说将向您介绍服务器程序怎么着利用线程池来优化品质并提供三个简便的线程池达成。

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

此处有个类为AutoResetEvent,他的功能是通报正在等待的线程已发出事变。他是从EventWaitHandle继承而来的!例子中分头用了二种分化的法子调用,第2种是足以传递参数的!工作线程1就传递了”作者的参数”字符串!工作线程2运作完了会打招呼等待的线程已发出事件.那里AutoReset伊夫nt开端化的时候首先将信号设成false,工作线程2如若调用成功,将被设成true. asyncOpIsDone.WaitOne()阻塞当前线程,直到收到信号!

  ① 、线程池管理器(ThreadPoolManager):用于创建并管理线程池

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

再看上边包车型客车例证

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

通过以下多个主意能够读取和设置CL瑞虎线程池云南中华工程公司小编线程与I/O线程的最大线程数。

 

  ③ 、任务接口(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 设置线程池最少需要保留的线程数

 

  特点:

作者们能够使用线程池来消除地点的大部难点,跟使用单个线程比较,使用线程池有如下优点:

运作结果为

  • 四个进度有且只有贰个线程池。
  • 线程池线程皆今后台线程(即不会堵住进程的停下)
  • 每一个线程都接纳暗中认可堆栈大小,以暗许的先行级运转,并处在多线程单元中。当先最大值的其余线程须求排队,但它们要等到其余线程完毕后才开动。
  • 在CLHighlander 2.0 SP1以前的版本中,线程池中 暗中同意最大的线程数量 = 处理器数 *
    25, CL冠道 2.0 SP1之后就改为了 暗许最大线程数量 = 处理器数 *
    250,线程上限能够变动,通过使用ThreadPool.Get马克斯+Threads和ThreadPool.Set马克斯Threads方法,能够取得和设置线程池的最大线程数。
  • 私下认可意况下,每一种处理器维持八个空暇线程,即私下认可最小线程数 =
    处理器数。
  • 当进度运转时,线程池并不会自动成立。当第③次将回调方法排入队列(比如调用ThreadPool.QueueUserWorkItem方法)时才会创立线程池。
  • 在对1个办事项进行排队之后将不可能撤销它。
  • 线程池中线程在完成义务后并不会自行销毁,它会以挂起的情形再次回到线程池,借使应用程序再度向线程池发出请求,那么那个挂起的线程将激活并实施任务,而不会创立新线程,那将节省了成百上千支付。唯有线程达到最大线程数量,系统才会以一定的算法销毁回收线程。

一 、收缩应用程序的响应时间。因为在线程池中有线程的线程处于等候分配职务状态(只要没有超越线程池的最大上限),无需成立线程。

 


② 、不必管理和掩护生活周期短暂的线程,不用在创建时为其分配财富,在其履行完职务之后自由财富。

4858.com 11

  哪天使用线程池?**  **

三 、线程池会依据当前系统本性对池内的线程进行优化处理。

本例中得以详细看AutoRest伊芙nt的用法MyWork1实际上先结束的,可是asyncOpIsDone要求等MyWork的信号!所以先输出了MyWork结束.那里还有2个东西笔者想说的就是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)

  ●假设需求使1个任务具有一定优先级

一旦急需传递职分音信能够使用WaitCallback中的state参数,类似于ParameterizedThreadStart委托。

  ●借使拥有或然会长时间运作(并因此阻塞其他任务)的天职

下边是贰个ThreadPool的例子,代码如下:

  ●假若须求将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)

4858.com 124858.com 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

  线程池常用艺术介绍?

4858.com 144858.com 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)

 

                  参数1:workerThreads
:线程池中扶助线程的最大数量。 
                  参数2:completionPortThreads :线程池中异步 I/O
线程的最大数量。 

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

 

4858.com 164858.com 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)
    参数1:workerThreads:当前由线程池维护的空闲辅助线程的纤维数目。 
    参数2:completionPortThreads:当前由线程池维护的悠闲异步 I/O
    线程的微乎其微数目。 

Program

 

 

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

线程池中放入异步操作

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

4858.com 184858.com 19

             
 参数1:workerThreads::要由线程池维护的新的细微空闲扶助线程数。 
             
 参数2: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。 

4858.com 204858.com 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)

4858.com 224858.com 23

                参数1:workerThreads:可用支持线程的数据。 
                参数2: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()  
 将艺术排入队列以便执行。此办法在有线程池线程变得可用时实行。 

 

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

线程池中的撤消操作

                再次来到值:假如将艺术成功排入队列,则为 true;不然为
false。 

4858.com 244858.com 25

    • 重载方法2: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());
        }
    }
}

               参数2:state :包蕴方法所用数据的对象。 
               重临值:要是将艺术成功排入队列,则为 true;否则为
false。 
      备注:WaitCallback
回调方法必须与System.Threading.WaitCallback委托项目相匹配。

Program

         WaitCallback函数原型:public delegate void
WaitCallback(Object state);调用QueueUserWorkItem能够通过Object来向任务进度传递参数。假如任务过程要求八个参数,能够定义包括这几个多少的类,并将类的实例强制转换为Object数据类型。

 

 

Thread与ThreadPool的2特性质相比较

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

4858.com 264858.com 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

  ⑧ 、RegisterWaitForSingleObject()    
将点名的嘱托排队到线程池。当爆发以下情况之最近,援救线程将履行委托。

 

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

 


 

  线程池示例?

 

  我们先来看3个简单的线程实例:

 

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);
            }
        }
    }
}

4858.com 28

 

“End in Main”并从未在ThreadInvoke()方法中具有代码执行完以往才输出。

简单来讲Main方法和ThreadInvoke是并行执行的

 

  使用线程池改造下边包车型大巴演示:

    下面介绍了只是三个最简便的有关线程线程的例证,但在其实支出中动用的线程往往是大方的和更为复杂的,那时,每趟都创制线程、运营线程。从性质上来讲,这样做并不出彩(因为每使用贰个线程就要创立多个,需求占用系统开发);从操作上来讲,每趟都要运营,相比麻烦。为此引入的线程池的定义。

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);
            }
        }
    }
}

4858.com, 

Thread.Sleep(三千)那句话是必须的因为当Main方法甘休后,.Net环境会活动终止销毁线程池,为了确定保障实现线程池里的职分,所以主线程供给等待一段时间。 

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

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有