1、CLR线程池基础
建立和销毁线程是一个昂贵的操做,因此CLR管理了一个线程池(thread pool),能够将线程池当作一个黑盒。
CLR初始化时,线程池中是没有线程的。线程的初始化与其余线程同样,可是在完成任务之后,该线程不会自行销毁,而是以挂起的状态返回到线程池。直到应用程序再次向线程池发出请求时,线程池里挂起的线程就会再度激活执行任务。
2、 ThreadPool的简单使用
能够直接将一个运算放到线程池的队列中进行工做;
2.1 调用方式
向线程池的队列中添加一个”工做项“以及可选的状态数据,能够经过下面的两种方式来进行异步的操做:
public static bool QueueUserWorkItem(WaitCallback callBack);
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
2.2 使用示例编程
{ public static void Excute() { Console.WriteLine("Main Thread:开始队列进入一个异步线程;"); ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5); Console.WriteLine("Main Thread:作主线程的其余任务任务;"); //模拟其余任务 Thread.Sleep(10000); Console.WriteLine("Main Thread End;"); } private static void ComputeBoundOp(object state) { Console.WriteLine("In ComputeBoundOp: state={0}",state); //模拟其余任务 Thread.Sleep(20000); Console.WriteLine("ComputeBoundOp Thread End;"); } }
运行结果:c#
2.3 取消线程的操做 简单的操做实例
public class CancellationDemo { /// <summary> /// 构造一个CancellationTokenSource后,从它的Token属性中得到一个或多个CancellationToken实例,并传给你的操做,使操做能够取消 /// </summary> public static void CancellationGo() { //构造一个CancellationTokenSource CancellationTokenSource cts =new CancellationTokenSource(); //取消后的执行操做 cts.Token.Register(() => Console.WriteLine("canceled 1")); cts.Token.Register(() => Console.WriteLine("canceled 2")); //放入线程池开始工做 ThreadPool.QueueUserWorkItem(x => Count(cts.Token, 100)); Console.WriteLine("press to cancel the operation"); Console.ReadLine(); cts.Cancel(); } /// <summary> /// 计数 /// </summary> /// <param name="token"></param> /// <param name="countTo"></param> private static void Count(CancellationToken token,Int32 countTo) { for (int i = 0; i < countTo; i++) { if (token.IsCancellationRequested) { Console.WriteLine("count is cancelled"); break; } Console.WriteLine(i); Thread.Sleep(2000); } Console.WriteLine("count is done"); } }
运行结果:
多线程
3、Task
很容易调用ThreadPool的QueueUserWorkItem方法发起一次异步的运算;可是,没有内建的机制让你知道操做在何时完成,也没有机制在操做完成时得到返回值;为了克服一些限制,引入了任务概念;
Task类是封装的一个任务类,内部使用的是ThreadPool类,提供了内建机制,让你知道何时异步完成以及如何获取异步执行的结果,而且还能取消异步执行的任务。
3.1 使用task和ThreadPool来完成相同的任务:
ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);
new Task(ComputeBoundOp,5).Start();
Task.Run(() => ComputeBoundOp(5));
3.2 Task的简单使用异步
public class TaskDemo { public void Excute() { long input = 10000000; //建立一个task Task<Int64> t1 = new Task<Int64>((x) => Sum((Int64) x), input); t1.Start(); //显示等待任务执行完毕 t1.Wait(); Console.WriteLine("task1 result is {0},主线程Id:{1}", t1.Result,Thread.CurrentThread.ManagedThreadId); //演示能够取消的任务 CancellationTokenSource cst=new CancellationTokenSource(); //建立一个task Task<Int64> t2 = new Task<Int64>(()=> Sum(cst.Token,input)); t2.Start(); Thread.Sleep(1000); cst.Cancel(); Console.WriteLine("task2 result is {0}", t2.Result); } private static Int64 Sum(Int64 n) { Int64 sum = 0; for (;n>0; n--) { checked { sum += n; } } Console.WriteLine("计算线程Id:{0}",Thread.CurrentThread.ManagedThreadId); return sum; } //建立可取消的任务 private static Int64 Sum(CancellationToken ct, Int64 n) { Int64 sum = 0; for (; n > 0; n--) { // ct.ThrowIfCancellationRequested(); if (!ct.IsCancellationRequested) { checked { sum += n; } Thread.Sleep(10); } } return sum; } }
运行结果:
咱们能够发现,程序启动了一个新的线程来计算;
当咱们添加了取消操做时,运算结果不一样;
4、async和await
在.NET 4.5中引入的Async和Await两个新的关键字后,用户能以一种简洁直观的方式实现异步编程。甚至都不须要改变代码的逻辑结构,就能将原来的同步函数改造为异步函数。async
在内部实现上,Async和Await这两个关键字由编译器转换为状态机,经过System.Threading.Tasks中的并行类实现代码的异步执行。异步编程
4.1 一个简单的例子函数
public class DownLoadUrlAsync { public void Excute() { Console.WriteLine("this is before Excute,threadId is {0}", Thread.CurrentThread.ManagedThreadId); var t = GetUrl().ContinueWith(task => { Console.WriteLine("this is ContinueWith Excute,threadId is {0},result is {1}", Thread.CurrentThread.ManagedThreadId, task.Result); }); Console.WriteLine("this is Excute,threadId is {0},t IsCompleted is {1}", Thread.CurrentThread.ManagedThreadId,t.IsCompleted); } private static async Task<int> GetUrl() { var httpClient = new HttpClient(); var url = "https://www.cnblogs.com/"; Console.WriteLine("this is before GetUrl,threadId is {0}", Thread.CurrentThread.ManagedThreadId); var res = await httpClient.GetByteArrayAsync(url); Console.WriteLine("this is GetUrl,threadId is {0}", Thread.CurrentThread.ManagedThreadId); return res.Length; } }
运行结果:
this
经过结果能够发现,程序启用了新的线程来完成咱们的任务;url
5、小结
一、C#可使用多种语法实现多线程 Thread
,ThreadPool
,Task
,async await
;
二、多线程能够同时完成多个任务;可使程序的响应速度更快;可让占用大量处理时间的任务或当前没有进行处理的任务按期将处理时间让给别的任务;线程