.net Framework 4.0添加的一个重要功能是任务并行库(Task Parallel Library TPL),任务并行库(TPL)在两个方面对多线程进行了增强;一:简化了线程的创建和使用。二:自动利用多个处理器。任务并行库(TPL)在System.Threading.Tasks命名空间中定义,因此程序要添加对该命名空间的引用。
任务并行库(TPL)中的核心类是Task类,对于TPL来说基本执行单元由Task类而非Thread类封装,Task类不同Thread类,Task类是一个表示异步操作的抽象类,在Task类实例和执行线程之间的对应关系不一定是一对一的,因为任务的执行由任务调试程序管理,任务调试程序使用线程池来处理任务,这意味着一些任务可能共享下相同的线程。
一、创建Task类,并开始执行任务。
示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace TaskDemo { class Program { static void Main(string[] args) { Task writeTask = new Task(WriteSomething); writeTask.Start(); Console.WriteLine("writeTask Tag:" + writeTask.Id); //注释掉下面二条语句后主线程结束后任务就结束执行。 writeTask.Wait(); Console.ReadKey(); } static void WriteSomething() { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(500); } } } }
运行结果如下:
示例先创建了writeTask实例,然后调用Start()方法开始启动任务,需要注意Task与Thread不同没有Name属性,只有一个标识任务编号的Id属性,而Id值唯一和无序的。示例中有注释写到“注释掉下面二条语句后主程序结束后任务就结束执行”,可以尝试注释掉代码查看结果是在任务刚启动是主线程结束了,任务立刻结束执行。因此Main()方法中调用了Wait()方法等待任务执行结束后再继续执行主线程。
二、创建任务延续和Lambda表达式用任务
任务并行库(TPL)的一个创新且非常便利的功能就是创建任务延续,延续是在一个任务结束后自动开始下一个任务,延续的方式是通过Task类定义的ContinueWith()方法来实现。自从Lambda表达式引入以来在.net中使用非常广泛,特别是Linq中,在任务延续中也可以使用Lambda表达式用作延续任务。
示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace TaskDemo { class Program { static void Main(string[] args) { Task task = new Task(WriteSomething); Task task2 = task.ContinueWith(WriteSomethingAgain); Task lambdaTask = task.ContinueWith((first) => { for (int i = 0; i < 5; i++) { Console.WriteLine("lambad:" + i); Thread.Sleep(500); } }); task.Start(); Console.WriteLine("tag"); Console.ReadKey(); } static void WriteSomething() { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(500); } } static void WriteSomethingAgain(object param) { for (int i = 0; i < 6; i++) { Console.WriteLine("write again:"+i); Thread.Sleep(500); } } } }
运行结果:
示例中使用ContinueWith()方法在任务task结束WriteSomething()后,继续开始执行两个任务,分别使用了常规方法和Lambad表达式用执行的任务。
三、从任务返回值
任务返回值是一个非常有用的功能,一:可以使用任务计算的结果;二、主调线程将阻塞直到结果准备就绪,这意味着不需要特殊的同步来等待结果。要返回结果需要使用Task类的泛型形式创建一个任务,即Task<TResult>。Task<TResult> 实例可以用各种不同的方式创建。最常见的方法是使用任务的 Factory 属性检索可用来创建用于多个用途的任务的 TaskFactory<TResult> 实例
示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace TaskDemo { class Program { static void Main(string[] args) { //返回值是int类型的任务 Task<int> taskGetResult = Task<int>.Factory.StartNew(WriteSomethingAgain, 3); //返回值是Bool类型的任务 Task<bool> taskGetBool = Task<bool>.Factory.StartNew(WriteSomethingAgain); //通过taskGetResult.Result阻塞主调线程 Console.WriteLine("TaskGetResult Result:"+taskGetResult.Result); //通过taskGetBool.Result阻塞主调线程 Console.WriteLine("TaskGetResult Result:"+taskGetBool.Result); Console.ReadKey(); } static int WriteSomethingAgain(object param) { for (int i = 0; i < 6; i++) { Console.WriteLine("write again:"+i); Thread.Sleep(500); } return 10; } static bool WriteSomethingAgain() { for (int i = 0; i < 6; i++) { //Console.WriteLine("write again:" + i); Thread.Sleep(00); } return true; } } }
运行结果如下图:
四、取消任务
取消任务基于取消标志(cancellation Token),取消标志从取消标志源(CancellationTokenSource)获取,然后将这个标志传递给任务,任务中必须监视该标志以查看是否有取消请求,如果有取消标志就结束任务,也可以调用ThrowIfCancellationRequested()方法,这样取消代码也知道取消任务已经发生。
示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace TaskDemo { class Program { static void Main(string[] args) { CancellationTokenSource cancelTokenSource = new CancellationTokenSource(); Task task =Task.Factory.StartNew(MyTaskIfCancelHappenThrownExcetion,cancelTokenSource.Token, cancelTokenSource.Token); Thread.Sleep(2000); try { cancelTokenSource.Cancel(); Thread.Sleep(10); task.Wait(); } catch (Exception ex) { if (task.IsCanceled) { Console.WriteLine("Task has been canceled"); } } finally { task.Dispose(); cancelTokenSource.Dispose(); } Console.WriteLine("Exiting Main..."); Console.ReadKey(); } static void MyTaskIfCancelHappenThrownExcetion(object cancelToken) { CancellationToken token = (CancellationToken)cancelToken; for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) { Console.WriteLine("Cancel han been requested"); break; //注释break,去掉下面注释,程序会抛出异常,通过异常取消代码接收到取消事件发生。 //token.ThrowIfCancellationRequested(); } Console.WriteLine("No cancel requested current value:" + i); Thread.Sleep(500); } } } }
运行结果如下: