TPL(Task Parallel Library)
任務並行庫 (TPL) 是 System.Threading和 System.Threading.Tasks 命名空間中的一組公共類型和 API。 TPL 的目的是通過簡化將並行和並發添加到應用程序的過程來提高開發人員的工作效率。
使用線程池可以減少並行操作時操作系統資源的開銷,然而使用線程池並不簡單,從線程池的工作線程中獲取結果也並不容易。於是就有了TPL,TPL可被認為是線程池上的又一個抽象層,其對開發人員隱藏了與線程池交互的底層代碼,並提供了更細粒度的API。
TPL的核心概念是任務。一個任務代表了一個異步操作,該操作可以通過多種方式運行,可以使用或不使用獨立線程運行。
更詳細的說明,可以訪問
https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-programming/task-parallel-library-tpl
如何創建一個任務
使用Task.Run()方法或Task.Factory.StartNew方法。
創建一個控制台應用程序,輸入以下代碼
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //使用Task的構造函數 6 Task task1 = new Task(Task1Method); 7 task1.Start(); 8 9 //使用Task.Run 10 Task.Run(()=> Task2Method()); 11 12 //使用Task.Factory.StartNew 13 Task.Factory.StartNew(Task3Method); 14 15 Console.ReadLine(); 16 } 17 18 19 static void Task1Method() 20 { 21 Console.WriteLine($"task1 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); 22 } 23 24 static void Task2Method() 25 { 26 Console.WriteLine($"task2 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); 27 } 28 29 static void Task3Method() 30 { 31 Console.WriteLine($"task3 run in thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); 32 } 33 }
運行結果如下
以同步方式運行任務
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //主線程運行 6 TaskMethod("Task1"); 7 8 Task task2 = new Task(()=>TaskMethod("Task2")); 9 Task task3 = new Task(()=>TaskMethod("Task3")); 10 11 //(同步)主線程運行 12 task2.RunSynchronously(); 13 14 //(異步)線程池運行 15 task3.Start(); 16 } 17 18 static void TaskMethod(string name) 19 { 20 Console.WriteLine($"Task {name} is running on a thread id : {System.Threading.Thread.CurrentThread.ManagedThreadId}, " + 21 $"Is thread pool thread: {System.Threading.Thread.CurrentThread.IsThreadPoolThread}"); 22 System.Threading.Thread.Sleep(1000); 23 24 } 25 }
運行結果:
使用單獨線程的任務
如果任務的代碼將長時間運行,可以使用TaskCreationOptions.LongRunning來告訴任務創建一個新線程,而不是使用線程池中的線程
示例代碼如下
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); 6 var t1 = new Task(TaskMethod,TaskCreationOptions.LongRunning); 7 t1.Start(); 8 } 9 10 static void TaskMethod() 11 { 12 Console.WriteLine(System.Threading.Thread.CurrentThread.IsThreadPoolThread); 13 Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); 14 } 15 }
運行結果:
使用任務來執行操作
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 TaskMethod("Task1");//會阻塞主線程,直到耗時操作完成 6 7 Task<int> task = CreateTask("Task 2"); 8 Console.WriteLine(task.Status); 9 task.Start();//啟動任務,並不會阻塞主線程,會繼續往下執行 10 while(!task.IsCompleted) 11 { 12 Console.WriteLine(task.Status); 13 System.Threading.Thread.Sleep(1000); 14 } 15 Console.WriteLine(task.Status); 16 int result = task.Result; 17 Console.WriteLine($"Result is : {result}"); 18 } 19 20 static Task<int> CreateTask(string name) 21 { 22 return new Task<int>(()=> TaskMethod(name)); 23 } 24 25 static int TaskMethod(string name) 26 { 27 Console.WriteLine($"Task {name} is running on a thread id : {System.Threading.Thread.CurrentThread.ManagedThreadId}, Is thread pool thread: {System.Threading.Thread.CurrentThread.IsThreadPoolThread}"); 28 //模擬耗時操作 29 System.Threading.Thread.Sleep(10000); 30 return 0; 31 } 32 }
運行結果:
組合任務
使用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 }
運行結果: