多线程编程学习笔记——任务并行库(二)
接上文 多線程編程學習筆記——任務并行庫(一)
?
?
三、?? 組合任務
?
??????? 本示例是學習如何設置相互依賴的任務。我們學習如何創(chuàng)建一個任務的子任務,這個子任務必須在父任務執(zhí)行結束之后,再執(zhí)行。
?
1,示例代碼如下:
?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ThreadTPLDemo {class Program{static void Main(string[] args){Console.WriteLine("Task 組合操作 ————"); Task<string> task1 =CreateTask("Task1",3);Task<string> task2 = CreateTask("Task2", 2);//給task1創(chuàng)建一個延續(xù)操作(子操作)task1.ContinueWith(t => Console.WriteLine("task1子操作:{0},線程ID:{1},是不是線程池中的線程:{2}",t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread),TaskContinuationOptions.OnlyOnRanToCompletion); task1.Start();task2.Start();Thread.Sleep(TimeSpan.FromSeconds(4)); Task task3=task2.ContinueWith(t => Console.WriteLine("task2子操作:{0},線程ID:{1},是不是線程池中的線程:{2}",
t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread),
TaskContinuationOptions.OnlyOnRanToCompletion|TaskContinuationOptions.ExecuteSynchronously); task3.GetAwaiter().OnCompleted(() => Console.WriteLine("task3異步操作完成,線程ID:{0},是不是線程池中的線程:{1}",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread));Thread.Sleep(TimeSpan.FromSeconds(2));Console.WriteLine("--------------父子任務--------------"); var task5= new Task<string>(() => {var task6 = Task.Factory.StartNew(() => TaskOper("子任務Task6", 5), TaskCreationOptions.AttachedToParent);task6.ContinueWith(t=>TaskOper("延時操作 task7",2),TaskContinuationOptions.AttachedToParent);return TaskOper("task5", 2);});task5.Start();while (!task5.IsCompleted){Console.WriteLine(" task5狀態(tài)——{0}", task5.Status);Thread.Sleep(500);}Console.WriteLine(" ——task5狀態(tài)—{0}", task5.Status);string result = task5.Result;Console.WriteLine(" task5運行結果——{0}", result);Console.ReadKey();}private static string TaskOper(string name,int seconds){ Console.WriteLine("Task 線程 ID:{0} 上,是不是線程池中的線程:{1},名稱: {2}",Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread, name);Thread.Sleep(TimeSpan.FromSeconds(seconds));return string.Format("線程ID:{0},名稱:{1}:秒:{2}", Thread.CurrentThread.ManagedThreadId,name,seconds);}static Task<string> CreateTask(string name,int seconds){return new Task<string>(() => TaskOper(name,seconds));}} }
2.程序運行結果如下圖。
?
?
?????? 如結果所示,程序在啟動時創(chuàng)建了兩個任務task1與task2,并為第一個任務創(chuàng)建了一個子操作。啟動這兩個任務,然后等待4秒,然后給第task2運行子操作,并通過TaskContinuationOptions. OnlyOnRanToCompletion的選項嘗試同步執(zhí)行這個子操作。如果子操作的運行時間非常短,則以上方式非常有用,因為放在主線程中運行比放在線程池運行要快。
?
????? 如果我們注釋掉那等待4秒的代碼(藍色字體),task2這個操作就會被放到線程池中,如下圖。
?
?
?
????? 接著,我們對task2任務的子操作定義了一個子操作task3,對task3使用新的GetAwaiter和Oncompleted方法,來執(zhí)行一個后續(xù)操作。
?
?????? 最后我們創(chuàng)建了一個新的任務task5,通過TaskContinuationOptions. AttachedToParent選項來運行一個子任務task6與后續(xù)操作task7。
?
?
?
四、?? 將APM模式轉為任務
?
????????? 本示例,將上一篇(多線程編程學習筆記——線程池(一))中的(示例一線程池中調用委托)轉為任務。將APM轉換為TPL的關鍵是Task<T>.Factory.FromAsync()方法
?
?1.代碼如下:
?
?
?2.程序運行結果如下圖。
?
?????? 程序運行結果中可以看出來,task1中直接傳入了IAsyncResult和Func< IAsyncResult,string>,task1執(zhí)行委托的異步調用,正常。
?
??????? Task2與task1類似,只是使用了不同的FromAsync的方法重載,這個重載不允許指定一個將會在異步調用完成之后被調用的回調函數(shù)。我們在示例中使用后續(xù)操作代替了回調函數(shù)。如果必須使用回調函數(shù),可以使用類似task1的調用方式。
?
??????? Task3我們通過一個技巧實現(xiàn)了調用與FromAsync不兼容的委托。我們通過將EndInvoke封裝到一個lambda表達式中,從而適應FromAsync方法。
?
?
?
五、?? 將EAP模式轉換為任務
?
?????? 本示例,將上一篇(多線程編程學習筆記——線程池(三))中的(使用BackgroundWorker組件示例)轉為任務。
??????? 本示例是學習如何基于事件的異步轉換為TASK來運行。本示例的關鍵是使用TaskCompletionSource<T>,T是異步操作結果的類型。
?
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ThreadPoolDemo{ class Program{ static void Main(string[] args){Console.WriteLine(" 將EAP模式轉為Task。。。");var tcs = new TaskCompletionSource<int>();var worker = new BackgroundWorker();worker.DoWork += (sender, eventArgs) =>{eventArgs.Result = RunTask("后臺線程 1 ", 5);};worker.RunWorkerCompleted += (sender, eventArgs) =>{if (eventArgs.Error!=null){Console.WriteLine(" ——出錯—{0}", eventArgs.Error);tcs.SetException(eventArgs.Error);}elseif (eventArgs.Cancelled){Console.WriteLine(" ——取消—");tcs.SetCanceled();//取消 }else{Console.WriteLine(" ——設置結果值—{0}", eventArgs.Result);tcs.SetResult((int)eventArgs.Result);} };worker.RunWorkerAsync();int result = tcs.Task.Result;Console.WriteLine(" ——任務Task運行結果—{0}", result);Thread.Sleep(2000); Console.Read();} private static int RunTask(string name,int seconds){Console.WriteLine("Task {0} 運行在線程={1}中,是否在線程池 :{2}",name, Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread);Thread.Sleep(TimeSpan.FromSeconds(seconds));return 42 * seconds;}} }
?
2.程序運行結果如下圖。
?
?
?
????? 注:tcs.SetResult要封閉在try-catch中,以方便獲取異常。或者可以使用tcs.TrySetResult。
?
總結
以上是生活随笔為你收集整理的多线程编程学习笔记——任务并行库(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 印象笔记无法连服务器(internet
- 下一篇: echarts堆叠图tooltip中如何