任务并行库 (TPL)
原文链接:https://learn.microsoft.com/zh-cn/dotnet/standard/parallel-programming/task-parallel-library-tpl?redirectedfrom=MSDN
https://www.cnblogs.com/zhaotianff/p/10458075.html
任务并行库 (TPL) 是 System.Threading 和 System.Threading.Tasks 空间中的一组公共类型和 API。 TPL 的目的是通过简化将并行和并发添加到应用程序的过程来提高开发人员的工作效率。 TPL 动态缩放并发的程度以最有效地使用所有可用的处理器。 此外,TPL 还处理工作分区、ThreadPool 上的线程调度、取消支持、状态管理以及其他低级别的细节操作。 通过使用 TPL,你可以在将精力集中于程序要完成的工作,同时最大程度地提高代码的性能。
使用线程池可以减少并行操作时操作系统资源的开销,然而使用线程池并不简单,从线程池的工作线程中获取结果也并不容易。于是就有了TPL,TPL可被认为是线程池上的又一个抽象层,其对开发人员隐藏了与线程池交互的底层代码,并提供了更细粒度的API。
TPL的核心概念是任务。一个任务代表了一个异步操作,该操作可以通过多种方式运行,可以使用或不使用独立线程运行
如何创建一个任务
使用Task.Run()方法或Task.Factory.StartNew方法。
创建一个控制台应用程序,输入以下代码
class Program { static void Main(string[] args) { //使用Task的构造函数 Task task1 = new Task(Task1Method); task1.Start(); //使用Task.Run Task.Run(()=> Task2Method()); //使用Task.Factory.StartNew Task.Factory.StartNew(Task3Method); Console.ReadLine(); } static void Task1Method() { Console.WriteLine($"task1 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); } static void Task2Method() { Console.WriteLine($"task2 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); } static void Task3Method() { Console.WriteLine($"task3 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); } }
运行结果如下:
以同步方式运行任务
class Program { static void Main(string[] args) { //主线程运行 TaskMethod("Task1"); Task task2 = new Task(()=>TaskMethod("Task2")); Task task3 = new Task(()=>TaskMethod("Task3")); //(同步)主线程运行 task2.RunSynchronously(); //(异步)线程池运行 task3.Start(); } static void TaskMethod(string name) { Console.WriteLine($"Task {name} is running on a thread id : {System.Threading.Thread.CurrentThread.ManagedThreadId}, " + $"Is thread pool thread: {System.Threading.Thread.CurrentThread.IsThreadPoolThread}"); System.Threading.Thread.Sleep(1000); } }
运行结果:
使用单独线程的任务
如果任务的代码将长时间运行,可以使用TaskCreationOptions.LongRunning来告诉任务创建一个新线程,而不是使用线程池中的线程
示例代码如下
class Program { static void Main(string[] args) { Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); var t1 = new Task(TaskMethod,TaskCreationOptions.LongRunning); t1.Start(); } static void TaskMethod() { Console.WriteLine(System.Threading.Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); } }
运行结果:
使用任务来执行操作
class Program { static void Main(string[] args) { TaskMethod("Task1");//会阻塞主线程,直到耗时操作完成 Task<int> task = CreateTask("Task 2"); Console.WriteLine(task.Status); task.Start();//启动任务,并不会阻塞主线程,会继续往下执行 while(!task.IsCompleted) { Console.WriteLine(task.Status); System.Threading.Thread.Sleep(1000); } Console.WriteLine(task.Status); int result = task.Result; Console.WriteLine($"Result is : {result}"); } static Task<int> CreateTask(string name) { return new Task<int>(()=> TaskMethod(name)); } static int TaskMethod(string name) { Console.WriteLine($"Task {name} is running on a thread id : {System.Threading.Thread.CurrentThread.ManagedThreadId}, Is thread pool thread: {System.Threading.Thread.CurrentThread.IsThreadPoolThread}"); //模拟耗时操作 System.Threading.Thread.Sleep(10000); return 0; } }
运行结果:
组合任务
使用Task< TResult> . ContinueWith方法来创建当另一任务完成时可以执行的延续任务。
当task1执行完成后,把task1返回的结果传递到下一个任务
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Task<int> task1 = new Task<int>(()=> TaskMethod("Task1",1)); 6 7 8 task1.ContinueWith(x => Console.WriteLine($"The task1 result is {x.Result} " + 9 $"Thread id is : {System.Threading.Thread.CurrentThread.ManagedThreadId} " + 10 $"Is Thread pool thread : {System.Threading.Thread.CurrentThread.IsThreadPoolThread} "),TaskContinuationOptions.OnlyOnRanToCompletion); 11 //TaskContinuationOptions.OnlyOnRanToCompletion 指定只应在延续任务前面的任务已完成运行的情况下才安排延续任务。 12 //更多TaskContinuationOptions可以参考 13 //https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.taskcontinuationoptions?redirectedfrom=MSDN&view=netframework-4.8 14 15 task1.Start(); 16 } 17 18 static int TaskMethod(string name,int seconds) 19 { 20 Console.WriteLine($"Task {name} is running on thread id :{System.Threading.Thread.CurrentThread.ManagedThreadId} " + 21 $"Is thread pool thread:{System.Threading.Thread.CurrentThread.IsThreadPoolThread} "); 22 System.Threading.Thread.Sleep(TimeSpan.FromSeconds(seconds)); 23 return DateTime.Now.Second; 24 } 25 }
运行结果: