标签:
由CLR via C#(第三版) ,摘抄记录...
异步优点:在GUI应用程序中保持UI可响应性,以及多个CPU缩短一个耗时计算所需的时间。
1、CLR线程池基础:为提高性能,CLR包含了代码来管理他自己的线程池--线程的集合。每CLR一个线程池,这个线程池就由CLR控制的所有appDomain共享。如果你进程中有多个CLR,就有多个线程池。
CLR初始化时,池空,线程池维护一个操作请求队列。应用调用方法执行异步,将一个记录项(entry)追加到线程池的队列。线程池从队列提取记录项,派遣(dispatch)给一个线程池线程,如没有,则创建一个新线程。完成任务后线程不销毁,在线程池空闲等待响应另一个请求,这样提高性能。 当请求速度超过处理速度,就会创建额外线程。如果请求停止,线程空闲一段时间后,会自己醒来终止自己以释放资源。 线程池是启发式的,由任务多少,和可用CPU的多少,创建线程。
在内部,线程池将自己的线程分为 工作者(Worker)线程和I/0线程。
2、简单的计算限制操作
将一个异步的、计算限制的操作放到一个线程池的队列中,通常可以调用ThreadPool类定义的以下方法之一:
//将方法排入队列以便执行。此方法在有线程池线程变得可用时执行。 static Boolean QueueUserWorkItem(WaitCallback callBack); //将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。 static Boolean QueueUserWorkItem(WaitCallback callBack,Object state);
~~~~
模拟程序
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine("Main thread: queuing an asynchronous operation"); 6 ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5); 7 Console.WriteLine("Main thread: Doing other work here..."); 8 Thread.Sleep(10000); // 模拟其它工作 (10 秒钟) 9 //Console.ReadLine(); 10 } 11 12 // 这是一个回调方法,必须和WaitCallBack委托签名一致 13 private static void ComputeBoundOp(Object state) 14 { 15 // 这个方法通过线程池中线程执行 16 Console.WriteLine("In ComputeBoundOp: state={0}", state); 17 Thread.Sleep(1000); // 模拟其它工作 (1 秒钟) 18 19 // 这个方法返回后,线程回到线程池,等待其他任务 20 } 21 }
如果回调方法有异常,CLR会终止进程。
3、 执行上下文 每个线程都关联了一个执行上下文数据结构。执行上下文(execution context)包括的东西有:
线程执行代码时,有的操作会受到线程的执行上下文设置(尤其是安全设置)的影响。理想情况下,每当一个线程(初始线程)使用另一个线程(辅助线程)执行任务时,前者的执行上下文应该"流动"(复制)到辅助线程。这就确保辅助线程执行的任何操作使用的都是相同的安全设置和宿主设置。还确保了初始线程的逻辑调用上下文可以在辅助线程中使用。
默认情况下,CLR自动造成初始线程的执行上下文会"流动"(复制)到任何辅助线程。这就是将上下文信息传输到辅助线程,但这对损失性能,因为执行上下文中包含大量信息,而收集这些信息,再将这些信息复制到辅助线程,要耗费不少时间。如果辅助线程又采用更多的辅助线程,还必须创建和初始化更多的执行上下文数据结构。
System.Threading命名空间中有一个ExecutionContext类[管理当前线程的执行上下文],它允许你控制线程的执行上下文如何从一个线程"流动"(复制)到另一个线程。下面展示了这个类的样子:
1 public sealed class ExecutionContext : IDisposable, ISerializable 2 { 3 [SecurityCritical] 4 //取消执行上下文在异步线程之间的流动 5 public static AsyncFlowControl SuppressFlow(); 6 //恢复执行上下文在异步线程之间的流动 7 public static void RestoreFlow(); 8 //指示当前是否取消了执行上下文的流动。 9 public static bool IsFlowSuppressed(); 10 11 //不常用方法没有列出 12 }
可用这个类阻止一个执行上下文的流动,从而提升应用程序的性能。对于服务器应用程序,性能的提升可能非常显著。但是,客户端应用程序的性能提升不了多少。另外,由于SuppressFlow方法用[SecurityCritical]attribute进行了标识,所以在某些客户端应用程序(比如Silverlight)中是无法调用的。当然,只有在辅助线程不需要或者不防问上下文信息时,才应该组织执行上下文的流动。如果初始线程的执行上下文不流向辅助线程,辅助线程会使用和它关联起来的任何执行上下文。在这种情况下,辅助线程不应该执行要依赖于执行上下文状态(比如用户的Windows身份)的代码。
注意:添加到逻辑调用上下文的项必须是可序列化的。对于包含了逻辑调用上下文数据线的一个执行上下文,如果让它流动,可能严重损害性能,因为为了捕捉执行上下文,需对所有数据项进行序列化和反序列化。
下例展示了向CLR的线程池队列添加一个工作项的时候,如何通过阻止执行上下文的流动来影响线程逻辑调用上下文中的数据:
1 static void Main(string[] args) 2 { 3 // 将一些数据放到Main线程的逻辑调用上下文中 4 CallContext.LogicalSetData("Name", "Jeffrey"); 5 6 // 线程池能访问到逻辑调用上下文数据,加入到程序池队列中 7 ThreadPool.QueueUserWorkItem( 8 state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); 9 10 11 // 现在阻止Main线程的执行上下文流动 12 ExecutionContext.SuppressFlow(); 13 14 //再次访问逻辑调用上下文的数据 15 ThreadPool.QueueUserWorkItem( 16 state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); 17 18 //恢复Main线程的执行上下文流动 19 ExecutionContext.RestoreFlow(); 20 }
会得到一下结果:
Name=Jeffrey
Name=
虽然现在我们讨论的是调用ThreadPool.QueueUserWorkItem时阻止执行上下文的流动,但在使用Task对象(参见26.5节”任务“),以及在发起异步I/O操作(参见第27章“I/o限制的异步操作”)时,这个技术也会用到。
4、协作式取消 标准的取消模式,协作的,想取消的操作必须显式地支持取消。为长时间运行的的计算限制操作添加取消能力。
首先,先解释一下FCL提供的两个主要类型,它们是标准协作式取消模式的一部分。
1 public class CancellationTokenSource : IDisposable 2 { 3 //构造函数 4 public CancellationTokenSource(); 5 //获取是否已请求取消此 System.Threading.CancellationTokenSource 6 public bool IsCancellationRequested { get; } 7 //获取与此 System.Threading.CancellationTokenSource 关联的 System.Threading.CancellationToken 8 public CancellationToken Token; 9 //传达取消请求。 10 public void Cancel(); 11 //传达对取消的请求,并指定是否应处理其余回调和可取消操作。 12 public void Cancel(bool throwOnFirstException); 13 ... 14 }
这个对象包含了管理取消有关的所有状态。构造好一个CancellationTokenSource(引用类型)之后,可以从它的Token属性获得一个或多个CancellationToken(值类型)实例,并传给你的操作,使那些操作可以取消。以下是CancellationToken值类型最有用的一些成员:
1 public struct CancellationToken //一个值类型 2 { 3 //获取此标记是否能处于已取消状态,IsCancellationRequested 由非通过Task来调用(invoke)的一个操作调用(call) 4 public bool IsCancellationRequested { get; } 5 //如果已请求取消此标记,则引发 System.OperationCanceledException,由通过Task来调用的操作调用 6 public void ThrowIfCancellationRequested(); 7 //获取在取消标记时处于有信号状态的 System.Threading.WaitHandle,取消时,WaitHandle会收到信号 8 public WaitHandle WaitHandle { get; } 9 //返回空 CancellationToken 值。 10 public static CancellationToken None 11 //注册一个将在取消此 System.Threading.CancellationToken 时调用的委托。省略了简单重载版本 12 public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext); 13 14 //省略了GetHashCode、Equals成员 15 }
CancellationToken实例是一个轻量级的值类型,它包含单个私有字段:对它的CancellationTokenSource对象的一个引用。在一个计算限制操作的循环中,可以定时调用CancellationToken的IsCancellationRequested属性,了解循环是否应该提前终止,进而终止计算限制的操作。当然,提前终止的好处在于,CPU不再需要把时间浪费在你对其结果已经不感兴趣的一个操作上。现在,用一些示例代码演示一下:
~~~~~~待续。。。。
标签:
原文地址:http://www.cnblogs.com/dacude/p/4391393.html