首页 > 代码库 > 线程也疯狂------计算限制的异步操作

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

参考页面:

http://www.yuanjiaocheng.net/webapi/create-crud-api-1.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-get.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-post.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-put.html

http://www.yuanjiaocheng.net/webapi/create-crud-api-1-delete.html

前言

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

 

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)

 

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

 

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