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