线程也疯狂------计算限制的异步操作

2017-01-06 19:41:21来源:cnblogs.com作者:东秦男人人点击

前言

异步的限制操作主要作用于其他执行线程,例如规则检查、音频或视频数据转码以及生成图形略缩图,在金融和建筑工程应用程序中,计算限制的操作也是十分普遍的。

 

CLR线程池

线程池是你的应用程序能使用的线程的一个集合,每个线程池都是由CLR控制的所有AppDomain共享,如果一个进程加载了多个CLR,那么每个CLR都有它自己的线程池,CLR初始化时,线程池中本来没有线程,线程池的内部维护了一个队列请求,应用程序执行一个异步时,就调用某个方法,将一个记录项追加到线程池的队列中,线程池的代码从这个队列中提取记录项,将这个记录项派发给一个线程池线程,如果线程池中没有线程就创建新的线程,当任务执行后,线程并不会销毁,返回线程池,进入空闲状态,等待响应另一个请求,不再消耗额外的性能。

但是当一个线程闲着没事儿一段时间后,线程会自动释放资源,使用线程池的目的就是不用担心线程创建和销毁带来的性能损失。

 

简单的计算限制操作

ThreadPool类定义的一个方法:

static Boolean QueueUserWorkItem(WaitCallback callBack,object obj);

方法说明:向线程池中添加一个工作项以及可选的状态数据,然后执行此工作项,可向方法传递一个obj参数

代码演示

 1 class Program 2     { 3         static void Main(string[] args) 4         { 5             Console.WriteLine("程序开始执行"); 6             ThreadPool.QueueUserWorkItem(ComputerSort, 6); 7             Console.WriteLine("模拟其他操作执行5s"); 8             Thread.Sleep(5000); 9             Console.WriteLine("点击Enter退出程序");10             Console.ReadLine();11         }12 13         private static void ComputerSort(object obj)14         {15             Console.WriteLine("线程池开始执行 参数={0}",obj.ToString());16         }17     }

显示结果

我们发现输出的执行顺序会发生变化,是因为两个方法相互之间在异步上运行的,Windwos调度器决定具体先调度那个线程,如果是多核CPU可能同时调度它们。

执行上下文

每个线程都关联两个一个执行上下文数据结构,执行上下文包括:安全设置(压缩栈、Principal属性、Windows身份)、宿主设置以及逻辑调用上下文数据。

理想情况下,每当一个线程使用另一个线程(辅助线程)执行任务时,前者的执行上下文应该流向后者,确保辅助线程执行的操作都是使用的相同安全设置和宿主设置。

通过阻止执行上下文流动可以提升应用程序的性能,尤其是服务器应用性能提高显著,客户端的效果一般。

事例代码:

 

 1  static void Main(string[] args) 2         { 3  4             //将数据放入Main线程的逻辑上下文中 5             CallContext.LogicalSetData("Name","Tom"); 6  7             ThreadPool.QueueUserWorkItem(p => 8             { 9                 Console.WriteLine("Name = {0}",CallContext.LogicalGetData("Name"));10             });11 12             ExecutionContext.SuppressFlow();13 14             ThreadPool.QueueUserWorkItem(p =>15             {16                 Console.WriteLine("Name = {0}", CallContext.LogicalGetData("Name"));17             });18 19             ExecutionContext.RestoreFlow();20 21             ThreadPool.QueueUserWorkItem(p =>22             {23                 Console.WriteLine("Name = {0}", CallContext.LogicalGetData("Name"));24             });25 26             Console.ReadLine();27 28         }

 

协作式取消和超时

对于长时间运行的计算限制操作,支持取消是一个必要的操作,.Net提供了标准的取消操作模式,无论执行操作的代码,还是试图取消操作的代码,都必须使用下面介绍的类型。

System.Threading.CancellationTokenSource------->这个对象包含了管理取消有关的所有状态,可以从它的Token属性获得一个或者多个CancellationToken实例,

 1  static void Main(string[] args) 2         { 3             CancellationTokenSource  cts = new CancellationTokenSource(); 4  5             ThreadPool.QueueUserWorkItem(state => Count(cts.Token, 100)); 6  7             Console.WriteLine("输入Enter停止计算"); 8  9             Console.ReadLine();10 11             cts.Cancel();12 13             Console.ReadLine();14         }15 16         private static void Count(CancellationToken token,int count)17         {18             for (int i = 0; i <=count; i++)19             {20                 if (token.IsCancellationRequested)21                 {22                     Console.WriteLine("接收到取消信号");23                     break;24                 }25                 Console.WriteLine("i = {0}",i);26                 Thread.Sleep(1000);27             }28         }

如果愿意可调用CancellationTokenSource的Register方法登记一个或者多个在取消一个CancellationTokenSource时调用的方法,要向方法传递一个Action<object>委托,一个要通过委托方法传给回调,以及一个Boolean值,该值指明是否要使用调用线程的SynchroinzationContent来调用委托。

 

1  cts.Token.Register(() =>2             {3                 Console.WriteLine("接收到取消信号后,开始调用回调函数");4             });

 

 在很多情况下,我们需要在过一段时间之后才取消操作,例如服务器应用程序可能会根据客户端的请求进行计算,但必须在两秒内响应,无论是否完成必须结束此次会话。在.NET 4.5中,CacncellationTokenSource提送了一个CancelAfter的方法

1  public void CancelAfter(int millisecondsDelay)

 

本章节的内容就讲解到这里,下节我们将会继续 线程也疯狂-----任务。

 

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台