任务并行库 (TPL) 基于“任务”的概念,后者表示异步运算。 在某些方面,任务类似于线程或 ThreadPool 工作项,但是抽象级别更高。 术语“任务并行”是指一个或多个独立的任务同时运行。 任务提供两个主要好处:
-
系统资源的使用效率更高,可伸缩性更好。
在后台,任务排队到已使用算法增强的 ThreadPool,这些算法能够确定线程数并随之调整,提供负载平衡以实现吞吐量最大化。 这会使任务相对轻量,你可以创建很多任务以启用细化并行。
-
对于线程或工作项,可以使用更多的编程控件。
任务和围绕它们生成的框架提供了一组丰富的 API,这些 API 支持等待、取消、继续、可靠的异常处理、详细状态、自定义计划等功能。
出于这两个原因,在 .NET Framework 中,TPL 是用于编写多线程、异步和并行代码的首选 API。
不返回值的任务由 System.Threading.Tasks.Task 类表示。 返回值的任务由 System.Threading.Tasks.Task<TResult> 类表示,该类从 Task 继承。 任务对象处理基础结构详细信息,并提供可在任务的整个生存期内从调用线程访问的方法和属性。 例如,可以随时访问任务的 Status 属性,以确定它是已开始运行、已完成运行、已取消还是引发了异常。 状态由 TaskStatus 枚举表示。
在创建任务时,你赋予它一个用户委托,该委托封装该任务将执行的代码。 该委托可以表示为命名的委托、匿名方法或 lambda 表达式。 lambda 表达式可以包含对命名方法的调用,如下面的示例所示。 请注意,该示例包含对 Task.Wait 方法的调用,以确保任务在控制台模式应用程序结束之前完成执行。
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { Thread.CurrentThread.Name = "Main"; // Create a task and supply a user delegate by using a lambda expression. Task taskA = new Task( () => Console.WriteLine("Hello from taskA.")); // Start the task. taskA.Start(); // Output a message from the calling thread. Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name); taskA.Wait(); } } // The example displays the following output: // Hello from thread 'Main'. // Hello from taskA.
你还可以使用 Task.Run 方法通过一个操作创建并启动任务。 无论是哪个任务计划程序与当前线程关联,Run 方法都将使用默认的任务计划程序来管理任务。 不需要对任务的创建和计划进行更多控制时,首选 Run 方法创建并启动任务。
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { Thread.CurrentThread.Name = "Main"; // Define and run the task. Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA.")); // Output a message from the calling thread. Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name); taskA.Wait(); } } // The example displays the following output: // Hello from thread 'Main'. // Hello from taskA.
你还可以使用 TaskFactory.StartNew 方法在一个操作中创建并启动任务。 不必将创建和计划分开并且你需要其他任务创建选项或使用特定计划程序时,或者需要通过AsyncState 属性将其他状态传递到任务时,请使用此方法,如下例所示。
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { Thread.CurrentThread.Name = "Main"; // Better: Create and start the task in one operation. Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA.")); // Output a message from the calling thread. Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name); taskA.Wait(); } } // The example displays the following output: // Hello from thread 'Main'. // Hello from taskA.