异步编程,线程从陌生到熟悉

CL君越线程池并不会在CLLX570开头化时马上成立线程,而是在应用程序要创设线程来运转职责时,线程池才开端化三个线程。
线程池开端化时是平素不线程的,线程池里的线程的伊始化与其余线程同样,可是在成功任务之后,该线程不会自动销毁,而是以挂起的情事重返到线程池。直到应用程序再度向线程池发出必要时,线程池里挂起的线程就能够另行激活推行任务。
诸有此类既节约了创立线程所造成的性质损耗,也足以让多少个任务一再重用同一线程,进而在应用程序生存期内节约大量支出。

前些天大家来谈谈线程池:

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

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

澳门太阳娱乐官方网站 1

 从此现在图中我们会发觉 .NET 与C#
的每种版本发表都以有多个“宗旨”。即:C#1.0托管代码→C#2.0泛型→C#3.0LINQ→C#4.0动态语言→C#5.0异步编制程序。将来我为流行版本的“异步编制程序”核心写连串共享,期望您的查看及点评。

 

澳门太阳娱乐官方网站,前几日的应用程序更加的复杂,大家平日须求运用《异步编制程序:线程概述及使用》中涉及的多线程手艺来抓好应用程序的响应速度。那个时候大家往往的创设和销毁线程来让应用程序快捷响应操作,那往往的开创和销毁无疑会下跌应用程序品质,大家得以引进缓存机制消除这些主题素材,此缓存机制亟待消除如:缓存的轻重难点、排队执行职分、调解空闲线程、按需创建新线程及销毁多余空闲线程……这几天微软现已为我们提供了现存的缓存机制:线程池

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

流程图:

 澳门太阳娱乐官方网站 2

 

         对于对象池的清理经常设计二种办法:

1卡塔尔(英语:State of Qatar)         手动清理,即积极调用清理的诀要。

2卡塔尔(英语:State of Qatar)         自动清理,即通过System.Threading.Timer来完结定期清理。

 

根本实现代码:

 

  澳门太阳娱乐官方网站 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(卡塔尔(英语:State of Qatar){ } /// <summary> /// 释放该对象池 ///
</summary> public void Dispose(卡塔尔(قطر‎{ } /// <summary> ///
将对象池中内定的目的重新设置并设置为空闲状态 /// </summary> public
void ReturnOne(T obj卡塔尔{ } /// <summary> /// 手动清理对象池 ///
</summary> public void ManualReleaseObject(卡塔尔{ } ///
<summary> /// 自动清理对象池(对超过 最小容积 的悠闲对象实行自由)
/// </summary> private void AutoReleaseObject(Object obj){ } }
实现的首要代码

 

通过对“对象池”的一个大致认知能帮我们更加快掌握线程池。

 

线程池ThreadPool类详解

ThreadPool静态类,为应用程序提供四个由系统管理的辅助线程池,从而使您能够集中精力于应用程序职责并非线程管理。每种进度都有二个线程池,四个Process中一定要有二个实例,它在依次应用程序域(AppDomain)是分享的。

在内部,线程池将自个儿的线程划分工小编线程(协理线程卡塔尔(قطر‎和I/O线程。前边二个用于实行平常的操作,前者专用于异步IO,比方文件和互联网必要,注意,分类并不表明二种线程本身有差别,内部仍然为相通的。

澳门太阳娱乐官方网站 4public
static class ThreadPool { //
将操作系统句柄绑定到System.Threading.ThreadPool。 public static bool
BindHandle(SafeHandle osHandle卡塔尔(قطر‎; //
检索由ThreadPool.GetMaxThreads(Int32,Int32卡塔尔国方法再次回到的最大线程池线程数和当前活动线程数之间的差值。
public static void GetAvailableThreads(out int workerThreads , out int
completionPortThreads卡塔尔; //
设置和查找能够何况处于活动状态的线程池央求的数码。 //
全体大于此数量的央浼将维持排队情形,直到线程池线程变为可用。 public
static bool SetMaxThreads(int workerThreads, int completionPortThreads卡塔尔国;
public static void GetMaxThreads(out int workerThreads, out int
completionPortThreads卡塔尔(英语:State of Qatar); //
设置和检索线程池在新央求预测中保证的空闲线程数。 public static bool
SetMinThreads(int workerThreads, int completionPortThreads卡塔尔(قطر‎; public
static void GetMinThreads(out int workerThreads, out int
completionPortThreads卡塔尔(英语:State of Qatar); //
将艺术排入队列以便实施,并钦定富含该方式所用数据的目标。此方法在有线程池线程变得可用时推行。
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卡塔尔(英语:State of Qatar); // 注册四个守候Threading.WaitHandle的信托,并点名三个 三十三个人有标志整数来代表超时值(以皮秒为单位)。 // executeOnlyOnce若是为
true,表示在调用了信托后,线程将不再在waitObject参数上等候; // 假设为
false,表示每一回完结等待操作后都重新设置沙漏,直到裁撤等待。 public static
RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject
, WaitOrTimerCallback callBack, object state, Int
milliseconds提姆eOutInterval, bool executeOnlyOnce卡塔尔(英语:State of Qatar); public static
RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle
waitObject , WaitOrTimerCallback callBack , object state , int
milliseconds提姆eOutInterval , bool executeOnlyOnce卡塔尔(قطر‎; …… } ThreadPool

1卡塔尔国         使用GetMaxThreads(卡塔尔和SetMaxThreads(卡塔尔获取和设置最大线程数

可排队到线程池的操作数仅受内部存款和储蓄器的限量;而线程池约束进程中能够同不经常间处于活动状态的线程数(私下认可情形下,约束每一种CPU 能够动用 25 个工笔者线程和 1,000 个 I/O 线程(遵照机器CPU个数和.net
framework版本的两样,那个数据或许会有变化卡塔尔),全体大于此数额的倡议将保险排队情形,直到线程池线程变为可用。

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

a卡塔尔国        
将线程池大小设置得太大,大概会促成更频仍的奉行上下文切换及加强能源的争用境况。

b卡塔尔        
其实FileStream的异步读写,异步发送接收Web央求,System.Threading.Timer停车计时器,以至接收delegate的beginInvoke都会私下认可调用
ThreadPool,也等于说不仅仅你的代码或然行使到线程池,框架之中也可以有可能接受到。

c卡塔尔国        
贰个应用程序池是一个独自的进度,具备一个线程池,应用程序池中能够有多少个WebApplication,各种运营在二个单身的AppDomain中,那么些WebApplication公用贰个线程池。

 

2卡塔尔(قطر‎         使用GetMinThreads(卡塔尔(قطر‎和SetMinThreads(卡塔尔(英语:State of Qatar)获取和安装最小空闲线程数

为防止向线程分配无需的仓库空间,线程池根据一定的大运间隔创立新的悠闲线程(该间距为半秒)。所以生机勃勃旦最小空闲线程数设置的过小,在长期内施行大气任务会因为创造新空闲线程的停放延迟导致品质瓶颈。最小空闲线程数暗许值等于机械上的CPU核数,况且不提出纠正最小空闲线程数。

在开发银行线程池时,线程池具备一个放置延迟,用于启用最小空闲线程数,以增长应用程序的吞吐量。

在线程池运转中,对于执行完职责的线程池线程,不会马上销毁,而是重返到线程池,线程池会维护最小的空闲线程数(固然应用程序所有线程皆以悠闲状态卡塔尔(英语:State of Qatar),以便队列任务能够立即运转。超越此最小数指标空闲线程意气风发段时间没事做后会本身醒来终止本人,以节约系统能源。

3卡塔尔(قطر‎         静态方法GetAvailableThreads(卡塔尔(قطر‎

经过静态方法GetAvailableThreads(卡塔尔(英语:State of Qatar)重返的线程池线程的最大额和当下运动数量之间的差值,即获取线程池中当前可用的线程数目

4卡塔尔(英语:State of Qatar)         两个参数

方式GetMaxThreads(卡塔尔国、SetMaxThreads(卡塔尔、GetMinThreads(卡塔尔(英语:State of Qatar)、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(卡塔尔国为大家提供了生机勃勃种方法:在多个水源对象变得可用的时候调用二个格局。

使用需注意:

1卡塔尔(قطر‎         WaitOrTimerCallback委托参数,该信托选拔三个名称叫timeOut的Boolean参数。假如 WaitHandle 在指准时期内未有接超过实际信号(即,超时),则为true,不然为 false。回调方法能够凭仗timeOut的值来针对地采纳措施。

2卡塔尔         名称叫executeOnlyOnce的Boolean参数。传true则表示线程池线程只进行回调方法一回;若传false则象征内核对象每回接到时域信号,线程池线程都会施行回调方法。等待一个AutoResetEvent对象时,那个功能越发有用。

3卡塔尔         RegisterWaitForSingleObject(卡塔尔(قطر‎方法重返一个RegisteredWaitHandle对象的引用。这几个目的标志了线程池正在它上面等待的基石对象。大家得以调用它的Unregister(WaitHandle
waitObject卡塔尔方法打消由RegisterWaitForSingleObject(卡塔尔国注册的等候操作(即WaitOrTimerCallback委托不再实行卡塔尔国。Unregister(WaitHandle
waitObject卡塔尔的WaitHandle参数表示成功撤消注册的等候操作后线程池会向此指标发出复信号(set(卡塔尔(قطر‎卡塔尔国,若不想吸取此公告能够传递null。

         示例:

澳门太阳娱乐官方网站 5private
static void Example_RegisterWaitForSingleObject(卡塔尔(英语:State of Qatar) { //
加endWaitHandle的缘故:即便试行过快退出形式会形成一些事物被保释,产生排队的职责不能够执行,原因还在斟酌AutoReset伊夫nt endWaitHandle = new AutoReset伊芙nt(false卡塔尔; AutoReset伊芙nt
notificWaitHandle = new AutoReset伊夫nt(false卡塔尔(قطر‎; AutoResetEvent waitHandle
= new AutoResetEvent(false卡塔尔; RegisteredWaitHandle registeredWaitHandle =
ThreadPool.RegisterWaitForSingleObject( waitHandle, (Object state, bool
timedOut卡塔尔(قطر‎ => { if (timedOut卡塔尔国Console.WriteLine(“RegisterWaitForSingleObject因超时而实践”卡塔尔国; else
Console.WriteLine(“RegisterWaitForSingleObject收到WaitHandle模拟信号”卡塔尔国; },
null, 提姆eSpan.FromSeconds(2卡塔尔(قطر‎, true 卡塔尔(قطر‎; //
裁撤等待操作(即不再施行WaitOrTimerCallback委托)
registeredWaitHandle.Unregister(notificWaitHandle卡塔尔; // 通告ThreadPool.RegisterWaitForSingleObject( notificWaitHandle, (Object
state, bool timedOut卡塔尔(英语:State of Qatar) => { if (timedOut)Console.WriteLine(“第二个RegisterWaitForSingleObject未有调用Unregister(卡塔尔国”卡塔尔(英语:State of Qatar);
else
Console.WriteLine(“第壹个RegisterWaitForSingleObject调用了Unregister(卡塔尔(英语:State of Qatar)”卡塔尔(英语:State of Qatar);
endWaitHandle.Set(卡塔尔; }, null, TimeSpan.FromSeconds(4卡塔尔, 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决定再次调解同二个线程,那么Windows不会实施上下文切换。假若Windows调节了一个不豆蔻梢头的线程,此时Windows推行线程上下文切换。

        
当Windows上下文切换来另二个线程时,CPU将执行八个莫衷一是的线程,而此前线程的代码和数据还在CPU的高速缓存中,(高速缓存使CPU不必经常访谈RAM,RAM的速度比CPU高速缓存慢得多),当Windows上下文切换成三个新线程时,那一个新线程极有超大希望要施行不生机勃勃的代码并拜会差异的多少,这几个代码和数据不在CPU的高速缓存中。由此,CPU必须访谈RAM来填充它的高速缓存,以平复非常的慢实增势况。不过,在其“时间片”实行完后,一回新的线程上下文切换又生出了。

上下文切换所发出的付出不会换到任何内部存款和储蓄器和总体性上的收益。推行上下文所需的时刻决意于CPU架议和速度(即“时间片”的分配)。而填充CPU缓存所需的日子决意于系统运行的应用程序、CPU、缓存的尺寸以至此外各个因素。所以,不能够为每一回线程上下文切换的年华支出给出叁个分明的值,以至不恐怕提交三个推断的值。唯豆蔻年华分明的是,若是要营造高品质的应用程序和组件,就应有尽恐怕制止线程上下文切换。

除了那几个之外,试行垃圾回笼时,CL本田CR-V必得挂起(暂停卡塔尔(英语:State of Qatar)所有线程,遍历它们的栈来查找根以便对堆中的对象开展标志,再度遍历它们的栈(有的对象在收缩期间发生了移动,所以要更新它们的根卡塔尔,再回复所有线程。所以,收缩线程的数额也会刚烈晋级垃圾回笼器的习性。每便使用三个调节和测量试验器并境遇三个断点,Windows都会挂起正在调节和测量检验的应用程序中的所有线程,并在单步推行或运转应用程序时上升所有线程。因而,你用的线程越来越多,调试体验也就越差。

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

澳门太阳娱乐官方网站 6

在《异步编制程序:线程概述及选取》中小编关系了Thread的七个上下文,即:

1卡塔尔(قطر‎         CurrentContext       
获取线程正在内部实施的一时上下文。首要用于线程内部存款和储蓄数据。

2卡塔尔(قطر‎         ExecutionContext   
获取一个System.Threading.ExecutionContext对象,该指标包罗关于当前线程的各样上下文的新闻。首要用于线程间数据分享。

里头拿到到的System.Threading.ExecutionContext就是本小节要说的“推行上下文”。

澳门太阳娱乐官方网站 7public
sealed class ExecutionContext : IDisposable, ISerializable { public void
Dispose(卡塔尔国; public void GetObjectData(SerializationInfo info,
StreamingContext context卡塔尔(英语:State of Qatar); //
此方法对于将进行上下文从叁个线程传播到另一个线程特别实用。 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
类提供的遵从让客户代码能够在客户定义的异步点之间捕获和传导此上下文。公共语言运维时(CLPAJERO卡塔尔国确定保证在托管进度内运维时定义的异步点之间近似地传输
ExecutionContext。

每当叁个线程(带头线程卡塔尔(英语:State of Qatar)使用另叁个线程(帮助线程卡塔尔推行任务时,CL福睿斯会将后面一个的实践上下文流向(复制到)扶持线程(注意这一个活动流向是单方向的)。那就保证了救助线程实行的其余操作使用的是平等的平安设置和宿主设置。还保证了初叶线程的逻辑调用上下文能够在援救线程中利用。

但实践上下文的复制会招致一定的质量影响。因为奉行上下文中满含大批量音信,而访谈全数那么些消息,再把它们复制到扶持线程,要消耗点不清岁月。要是帮忙线程又采用了更多地拉扯线程,还非得创建和起首化越来越多的实行上下文数据结构。

进而,为了提高应用程序品质,大家可以阻止实行上下文的流动。当然那独有在协助线程无需只怕不访谈上下文音讯的时候手艺扩充拦截。

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

1卡塔尔         在线程间分享逻辑调用上下文数据(CallContext)。

2卡塔尔(英语:State of Qatar)         为了进步品质,阻止光复试行上下文的流动。

3卡塔尔(قطر‎         在日前线程上的钦赐实行上下文中运作某些方法。

澳门太阳娱乐官方网站 8private
static void Example_ExecutionContext(卡塔尔国 {
CallContext.LogicalSetData(“Name”, “小红”卡塔尔(قطر‎;
Console.WriteLine(“主线程中Name为:{0}”,
CallContext.LogicalGetData(“Name”卡塔尔(英语:State of Qatar)卡塔尔; // 1卡塔尔国在线程间分享逻辑调用上下文数据(CallContext)。
Console.WriteLine(“1卡塔尔(英语:State of Qatar)在线程间分享逻辑调用上下文数据(CallContext)。”卡塔尔国;
ThreadPool.QueueUserWorkItem((Object obj卡塔尔(英语:State of Qatar) =>
Console.WriteLine(“ThreadPool线程中Name为:”{0}””,
CallContext.LogicalGetData(“Name”卡塔尔(英语:State of Qatar)卡塔尔(英语:State of Qatar)卡塔尔(قطر‎; Thread.Sleep(500卡塔尔(قطر‎;
Console.WriteLine(卡塔尔(英语:State of Qatar); // 2卡塔尔(قطر‎ 为了进步质量,撤销东山再起试行上下文的流动。
ThreadPool.UnsafeQueueUserWorkItem((Object obj卡塔尔(英语:State of Qatar) =>
Console.WriteLine(“ThreadPool线程使用Unsafe异步实施形式来撤废实施上下文的流动。Name为:”{0}””
, CallContext.LogicalGetData(“Name”卡塔尔(قطر‎卡塔尔, null卡塔尔(英语:State of Qatar);
Console.WriteLine(“2卡塔尔为了进步品质,废除/恢复实施上下文的流动。”卡塔尔(英语:State of Qatar);
AsyncFlowControl flowControl = ExecutionContext.SuppressFlow(卡塔尔;
ThreadPool.QueueUserWorkItem((Object obj卡塔尔国 =>
Console.WriteLine(“(打消ExecutionContext流动卡塔尔(英语:State of Qatar)ThreadPool线程中Name为:”{0}””,
CallContext.LogicalGetData(“Name”卡塔尔国卡塔尔卡塔尔(قطر‎; Thread.Sleep(500卡塔尔国; //
复苏不引入使用ExecutionContext.RestoreFlow(卡塔尔 flowControl.Undo(卡塔尔(英语:State of Qatar);
ThreadPool.QueueUserWorkItem((Object obj卡塔尔国 =>
Console.WriteLine(“(复苏ExecutionContext流动卡塔尔(قطر‎ThreadPool线程中Name为:”{0}””,
CallContext.LogicalGetData(“Name”卡塔尔国卡塔尔国卡塔尔; Thread.Sleep(500卡塔尔国;
Console.WriteLine(卡塔尔(英语:State of Qatar); // 3卡塔尔在这时候此刻线程上的钦命施行上下文中运作某些方法。(通过得到调用上下文数据注明卡塔尔国Console.WriteLine(“3卡塔尔(قطر‎在前段时间线程上的钦赐实行上下文中运维有个别方法。(通过得到调用上下文数据他们表达卡塔尔(قطر‎”卡塔尔(قطر‎;
ExecutionContext curExecutionContext = ExecutionContext.Capture(卡塔尔;
ExecutionContext.SuppressFlow(卡塔尔国; ThreadPool.QueueUserWorkItem( (Object
obj卡塔尔(英语:State of Qatar) => { ExecutionContext innerExecutionContext = obj as
ExecutionContext; ExecutionContext.Run(innerExecutionContext, (Object
state卡塔尔国 =>
Console.WriteLine(“ThreadPool线程中Name为:”{0}””<br> ,
CallContext.LogicalGetData(“Name”)), null); } , curExecutionContext ); }
View Code

结果如图:

澳门太阳娱乐官方网站 9

 

 

 注意:

1卡塔尔(قطر‎        
示例中“在现阶段线程上的钦赐实践上下文中运营有些方法”:代码中必得使用ExecutionContext.Capture(卡塔尔(قطر‎获取当前执行上下文的二个副本

a卡塔尔        
若直接运用Thread.CurrentThread.ExecutionContext则会报“不只怕利用以下上下文:
跨 AppDomains 封送的上下文、不是透过捕获操作获取的上下文或已作为 Set
调用的参数的上下文。”错误。

b卡塔尔(英语:State of Qatar)        
若使用Thread.CurrentThread.ExecutionContext.CreateCopy(卡塔尔国会报“只可以复制新近捕获(ExecutionContext.Capture(卡塔尔(قطر‎卡塔尔(英语:State of Qatar)的上下文”。

2卡塔尔        
废除实践上下文流动除了使用ExecutionContext.SuppressFlow(卡塔尔方式外。仍然为能够通过应用ThreadPool的UnsafeQueueUserWorkItem

UnsafeRegisterWaitForSingleObject来实行委托方法。原因是不安全的线程池操作不会传导压缩货仓。每当压缩仓库流动时,托管的中央、同步、区域安装和客户上下文也跟着流动。

 

线程池线程中的万分

线程池线程中未管理的充裕将结束进度。以下为此法则的三种例外情形: 

  1. 是因为调用了 Abort,线程池线程上将吸引ThreadAbortException。 
    2.
    出张永琛值卸载应用程序域,线程池线程中将引发AppDomainUnloadedException。 
  2. 国有语言运行库或宿主进度将告风姿洒脱段落线程。

哪天不使用线程池线程

今后我们都早就知道线程池为大家提供了福利的异步API及托管的线程管理。那么是还是不是任曾几何时候都应有使用线程池线程呢?当然不是,大家照旧要求“量体裁衣”的,在以下两种情状下,相符于创立并管制本人的线程而不是使用线程池线程:

 

 

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

线程池尽管为大家提供了异步操作的造福,但是它不扶植对线程池中单个线程的目眩神摇调整导致大家有个别情形下会一贯动用Thread。並且它对“等待”操作、“撤销”操作、“三回九转”职务等操作相比麻烦,或许促令你从新造轮子。微软也想到了,所以在.NET4.0的时候踏向了“并行职分”并在.NET4.5中对其张开修改,想精通“并行职责”的园友能够先看看《(译)关于Async与Await的FAQ》。

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

 

 

 

 

参照他事他说加以考察资料:《CLMurano via C#(第三版)》

 

 摘自:

 

异步编制程序:使用线程池管理线程 从今现在图中大家会开采 .NET 与C#
的各样版本公布都是有多个宗旨…

透过CLRAV4线程池所确立的线程总是默认为后台线程,优先级数为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 线程的数额。
GetMaxThreads方法赢得当前由线程池维护的支持线程的最大数目.参数
workerThreads: 线程池中国救亡剧团助线程的最大额。completionPortThreads:
当前由线程池维护的空余异步 I/O 线程的最大数量。
GetMinThreads方法取稳妥前由线程池维护的悠闲扶助线程的蝇头数目.参数
workerThreads:
当前由线程池维护的闲暇协理线程的一丁点儿数目.completionPortThreads:
当前由线程池维护的空闲异步 I/O 线程的小小数目。
QueueUserWorkItem方法将艺术排入队列以便推行。参数callBack,
表示要试行的方法.state:包括方法所用数据的目的。
上边看个例证:

CLTiguan线程池分为劳动力线程(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 }
  • 劳引力线程是人命关天用作管理CLTiggo内部对象的运行,平日用于计算密集的职务。
  • I/O(Input/Output)线程根本用于与外表系统相互消息,如输入输出,CPU仅需在义务初叶的时候,将职责的参数字传送递给设备,然后运转硬件装置就能够。等职务到位的时候,CPU收到三个通报,一般的话是三个硬件的间歇复信号,那个时候CPU继续后继的拍卖职业。在管理进程中,CPU是不必完全参预管理进程的,若是正在运作的线程不交出CPU的调控权,那么线程也只可以处于等候情状,即使操作系统将最近的CPU调整给此外线程,这时线程所据有的半空中依然被占用,而并不曾CPU管理这一个线程,也许现身线程资源浪费的标题。假若那是三个网络服务程序,每七个网络连接都采纳一个线程处理,或然现身多量线程都在守候网络通讯,随着网络连接的连绵不断加码,处于等候处境的线程将会很开销尽全数的内部存款和储蓄器财富。能够思考使用线程池撤消那个难题。

 

  线程池的最大值平常默以为1000、二零零三。当不独有此数额的号召时,将保障排队状态,直到线程池里无线程可用。

 运营的结果为

  使用CLENVISION线程池的工作者线程平日常有三种方法:

澳门太阳娱乐官方网站 10

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

那边有个类为AutoResetEvent,他的效率是打招呼正在等候的线程已发闹事件。他是从EventWaitHandle世襲而来的!例子中分头用了三种差异的措施调用,第两种是足以传递参数的!专业线程1就传递了”作者的参数”字符串!工作线程2周转完了会通报等待的线程已发出事件.这里AutoReset伊夫nt起头化的时候首先将功率信号设成false,职业线程2即便调用成功,将被设成true. asyncOpIsDone.WaitOne(卡塔尔(قطر‎梗塞当前线程,直到收到功率信号!

  要小心,无论是因而ThreadPool.QueueUserWorkItem(卡塔尔(英语:State of Qatar)照旧委托,调用的都以线程池里的线程。

再看下边包车型地铁例子

经过以下多个法子能够读取和装置CL凯雷德线程池黑龙江中华南理工学院程公司作者线程与I/O线程的最大线程数。

 

  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 设置线程池最少需要保留的线程数

 

咱俩得以使用线程池来缓和地方的许多难点,跟使用单个线程相比较,使用线程池有如下优点:

运维结果为

1、收缩应用程序的响合时间。因为在线程池中有线程的线程处于等候分配义务状态(只要未有抢先线程池的最大上限),没有必要创立线程。

 

2、不必管理和维护生活周期短暂的线程,不用在开创时为其分配能源,在其举办完职务之后自由能源。

澳门太阳娱乐官方网站 11

3、线程池会依照当前系统个性对池内的线程进行优化管理。

本例中能够详细看AutoRestEvent的用法MyWork1其实先结束的,可是asyncOpIsDone须求等MyWork的数字信号!所以先输出了MyWork甘休.这里还会有四个事物笔者想说的就是WaitHandle,上边的例子已经付出了她的用法!他是AutoRsetEvent的基类.

简单的说使用线程池的效果与利益正是裁减创立和销毁线程的种类开辟。在.NET中有二个线程的类ThreadPool,它提供了线程池的管住。

再有ThreadPool有四个函数RegisterWaitForSingleObject这些函数还是满风趣的!作者那边就不再给出例子了!

ThreadPool是叁个静态类,它从不构造函数,对外提供的函数也全都以静态的。个中有三个QueueUserWorkItem方法,它有三种重载格局,如下:

好了,明日就到那了!

public static bool QueueUserWorkItem(WaitCallback
callBack卡塔尔(قطر‎:将艺术排入队列以便实行。此方式在有线程池线程变得可用时实践。

public static bool QueueUserWorkItem(WaitCallback
callBack,Object
state卡塔尔(英语:State of Qatar):将艺术排入队列以便实践,并钦命满含该办法所用数据的指标。此措施在有线程池线程变得可用时施行。

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

Program

 

应用ThreadPool调用工作线程和IO线程的模范

澳门太阳娱乐官方网站 16澳门太阳娱乐官方网站 17

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

Program

 

线程池中放入异步操作

澳门太阳娱乐官方网站 18澳门太阳娱乐官方网站 19

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

 

线程池同步操作

澳门太阳娱乐官方网站 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();


        }
    }
}

ThreadPoolDemo

澳门太阳娱乐官方网站 22澳门太阳娱乐官方网站 23

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

 

线程池中的撤消操作

澳门太阳娱乐官方网站 24澳门太阳娱乐官方网站 25

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 operationn");
            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());
        }
    }
}

Program

 

Thread与ThreadPool的几天性能比较

澳门太阳娱乐官方网站 26澳门太阳娱乐官方网站 27

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