版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Task類(lèi)使用總結(jié) 2012-12-27 20:51:19標(biāo)簽:C# 多線程 Task 并行 原創(chuàng)作品,允許轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章 原始出處 、作者信息和本聲明。否則將追究法律責(zé)任。 由于Framework 4.0和Framework 4.5對(duì)Task類(lèi)稍微有些不同,此處聲明以下代碼都是基于Framework 4.5Task類(lèi)和Task<TResult>類(lèi),后者是前者的泛型版本。TResult類(lèi)型為T(mén)ask所調(diào)用方法的返回值。主要區(qū)別在于Task構(gòu)造函數(shù)接受的參數(shù)是Action委托,而Task<TResult>接受的是Func<TResult>
2、;委托。1. Task(Action) 2. Task<TResult>(Func<TResult>) 啟動(dòng)一個(gè)任務(wù) 1. static void Main(string args) 2. 3. Task Task1 =&
3、#160;new Task() => Console.WriteLine("Task1"); 4. Task1.Start(); 5. Console.ReadLine(); 6.
4、0; 通過(guò)實(shí)例化一個(gè)Task對(duì)象,然后Start,這種方式中規(guī)中矩,但是實(shí)踐中,通常采用更方便快捷的方式Task.Run() => Console.WriteLine("Foo");這種方式直接運(yùn)行了Task,不像上面的方法還需要調(diào)用Start();Task.Run方法是Task類(lèi)中的靜態(tài)方法,接受的參數(shù)是委托。返回值是為該Task對(duì)象。Task.Run(Action)Task.Run<TResult>(Func<Task<TResult>>)Task構(gòu)造方法還有一個(gè)重載函數(shù)
5、如下:Task 構(gòu)造函數(shù) (Action, TaskCreationOptions),對(duì)應(yīng)的Task泛型版本也有類(lèi)似構(gòu)造函數(shù)。TaskCreationOptions參數(shù)指示Task創(chuàng)建和執(zhí)行的可選行為。常用的參數(shù)LongRunning。默認(rèn)情況下,Task任務(wù)是由線程池線程異步執(zhí)行的。如果是運(yùn)行時(shí)間很長(zhǎng)的操作,使用LongRunning 參數(shù)暗示任務(wù)調(diào)度器,將這個(gè)任務(wù)放在非線程池上運(yùn)行。通常不需要用這個(gè)參數(shù),除非通過(guò)性能測(cè)試覺(jué)得使用該參數(shù)能有更好的性能,才使用。任務(wù)等待默認(rèn)情況下,Task任務(wù)是由線程池線程異步執(zhí)行。要知道Task任務(wù)的是否完成,可以通過(guò)task.IsCompleted屬性獲得
6、,也可以使用task.Wait來(lái)等待Task完成。Wait會(huì)阻塞當(dāng)前線程。 1. static void Main(string args) 2. 3. Task Task1=Task.Run() => Thread.Sleep(5000);
7、0;4. Console.WriteLine("Foo"); 5. Thread.Sleep(5000); 6. &
8、#160; ); 7. Console.WriteLine(Task1.IsCompleted); 8. Task1.Wait();/阻塞當(dāng)前線程 9.
9、; Console.WriteLine(Task1.IsCompleted); 10. Wait方法有個(gè)重構(gòu)方法,簽名如下:public bool Wait(int millisecondsTimeout),接受一個(gè)時(shí)間。如果在設(shè)定時(shí)間內(nèi)完成就返回true,否則返回false。如下的代碼:1. static void Main(string args) 2.
10、; 3. Task Task1=Task.Run() => Thread.Sleep(5000); 4. Console.WriteLine("Foo"); 5. &
11、#160; Thread.Sleep(5000); 6. ); 7. 8. Console.Write
12、Line("Task1.IsCompleted:0",Task1.IsCompleted); 9. bool b=Task1.Wait(2000); 10. Console.WriteLine("Task1.IsCompleted:0",
13、160;Task1.IsCompleted); 11. Console.WriteLine(b); 12. Thread.Sleep(9000); 13.
14、60; Console.WriteLine("Task1.IsCompleted:0", Task1.IsCompleted); 14. 運(yùn)行結(jié)果為:獲得返回值 要獲得返回值,就要用到Task的泛型版本了。 1. static void Main(string args) 2. 3.
15、 Task<int> Task1 = Task.Run<int>() => Thread.Sleep(5000); return Enumerable.Range(1, 100).Sum(); ); 4. &
16、#160; Console.WriteLine("Task1.IsCompleted:0",Task1.IsCompleted); 5. Console.WriteLine("Task1.IsCompleted:0", Task1.Result);/如果方法未完成,則會(huì)等待直到計(jì)算完成,得到返回值才運(yùn)行下去。 6.
17、; Console.WriteLine("Task1.IsCompleted:0", Task1.IsCompleted); 7. 結(jié)果如下:異常拋出和線程不同,Task中拋出的異??梢圆东@,但是也不是直接捕獲,而是由調(diào)用Wait()方法或者訪問(wèn)Result屬性的時(shí)候,由他們獲得異常,將這個(gè)異常包裝成AggregateException類(lèi)型,再重新拋出捕獲
18、。 1. static void Main(string args) 2. 3. try 4. 5.
19、60; Task<int> Task1 = Task.Run<int>() => throw new Exception("xxxxxx"); return 1; ); 6. &
20、#160; Task1.Wait(); 7. 8. catch (Exception ex)/error的類(lèi)型為System.AggregateException 9.
21、0; 10. Console.WriteLine(ex.StackTrace); 11.
22、; Console.WriteLine("-"); 12. Console.WriteLine(ex.InnerException.StackTrace); 13. 14.
23、160; 如上代碼,運(yùn)行結(jié)果如下:可以看到異常真正發(fā)生的地方。對(duì)于某些匿名的Task(通過(guò) Task.Run方法生成的,不調(diào)用wait,也不關(guān)心是否運(yùn)行完成),某些情況下,記錄它們的異常錯(cuò)誤也是有必要的。這些異常稱作未觀察到的異常(unobserved exceptions)??梢酝ㄟ^(guò)訂閱一個(gè)全局的靜態(tài)事件TaskScheduler.UnobservedTaskException來(lái)處理這些異常。只要當(dāng)一個(gè)Task有異常,并且在被垃圾回收的時(shí)候,才會(huì)觸發(fā)這一個(gè)事件。如果Task還處于被引用狀態(tài),或者只要GC不回收這
24、個(gè)Task,這個(gè)UnobservedTaskException事件就不會(huì)被觸發(fā)例子: 1. static void Main(string args) 2. 3. TaskScheduler.UnobservedTaskException += UnobservedTaskEx
25、ception; 4. Task.Run<int>() => throw new Exception("xxxxxx"); return 1; ); 5. Thread.S
26、leep(1000); 6. 7. 8. static void UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) 9.
27、0;10. Console.WriteLine(e.Exception.Message); 11. Console.WriteLine(e.Exception.InnerException.Message); 12. &
28、#160; 這樣的代碼直到程序運(yùn)行完成也為未能觸發(fā)UnobservedTaskException,因?yàn)镚C沒(méi)有開(kāi)始做垃圾回收。在代碼中加入 GC.Collect(); 1. static void Main(string args) 2. 3. TaskScheduler.U
29、nobservedTaskException += UnobservedTaskException; 4. Task.Run<int>() => throw new Exception("xxxxxx"); return 1; ); 5.
30、0; Thread.Sleep(1000); 6. GC.Collect(); 7. GC.WaitForPendingFinalizers(); 8.
31、; 運(yùn)行后得到如下:延續(xù)任務(wù)延續(xù)任務(wù)就是說(shuō)當(dāng)一個(gè)Task完成后,繼續(xù)運(yùn)行下一個(gè)任務(wù)。通常有2種方法實(shí)現(xiàn)。一種是使用GetAwaiter方法。GetAwaiter方法返回一個(gè)TaskAwaiter結(jié)構(gòu),該結(jié)構(gòu)有一個(gè)OnCompleted事件,只需對(duì)OnCompleted事件賦值,即可在完成后調(diào)用該事件。 1. static void Main(string args) 2. 3. &
32、#160; Task<int> Task1 = Task.Run<int>() => return Enumerable.Range(1, 100).Sum(); ); 4. var
33、awaiter = Task1.GetAwaiter(); 5. awaiter.OnCompleted() => 6. 7.
34、0; Console.WriteLine("Task1 finished"); 8. int result = awaiter.GetResult(); 9. &
35、#160; Console.WriteLine(result); / Writes result 10. ); 11. Thread.Sleep(1000); 12. &
36、#160; 運(yùn)行結(jié)果如下:此處調(diào)用GetResult()的好處在于,一旦先前的Task有異常,就會(huì)拋出該異常。而且該異常和之前演示的異常不同,它不需要經(jīng)過(guò)AggregateException再包裝了。另一種延續(xù)任務(wù)的方法是調(diào)用ContinueWith方法。 ContinueWith返回的任然是一個(gè)Task類(lèi)型。ContinueWith方法有很多重載,算上泛型版本,差不多40個(gè)左右的。其中最常用的,就 是接受一個(gè)Action或者Func委托,而且,這些委托的第一個(gè)傳入?yún)?shù)都是Task類(lèi)型,即可以訪問(wèn)先前
37、的Task對(duì)象。示例: 1. static void Main(string args) 2. 3. Task<int> Task1 = Task.Run<int>() => return Enumerabl
38、e.Range(1, 100).Sum(); ); 4. Task1.ContinueWith(antecedent => 5. Console.WriteLine(antecedent.Result); 6. Console.WriteLine("Runing Continue Task"); 7. ); 8. &
39、#160; Thread.Sleep(1000); 9. 使用這種ContinueWith方法和GetAwaiter都能實(shí)現(xiàn)相同的效果,有點(diǎn)小區(qū)別就是ContinueWith如果獲取Result的時(shí)候有異常,拋出的異常類(lèi)型是經(jīng)過(guò)AggregateException包裹的,而GetAwaiter()后的OnCompleted所調(diào)用的方法中,如果出錯(cuò),直
40、接拋出異常。 生成Task的另一種方法,TaskCompletionSource 使用TaskCompletionSource很簡(jiǎn)單,只需要實(shí)例化它即可。TaskCompletionSource有一個(gè)Task屬性,你可以 對(duì)該屬性暴露的task做操作,比如讓它wait或者ContinueWith等操作。當(dāng)然,這個(gè)task由TaskCompletionSource完 全控制。TaskCompletionSource<TResult>類(lèi)中有一些成員方法如下:1. public class TaskCompletionSource<TResu
41、lt> 2. 3. public void SetResult (TResult result); 4. public void SetException (Exception exception); 5. public void SetCanceled(); 6. public bool TrySetResult (TResult result); 7. public bool
42、 TrySetException (Exception exception); 8. public bool TrySetCanceled(); 9. . 10. 調(diào)用以上方法意味著對(duì)Task做狀態(tài)的改變,將狀態(tài)設(shè)成completed,faulted或者 canceled。這些方法只能調(diào)用一次,不然會(huì)有異常。Try的方法可以調(diào)多次,只不過(guò)返回false而已。通過(guò)一些技巧性的編碼,將線程和Task協(xié)調(diào)起來(lái),通過(guò)Task獲得線程運(yùn)行的結(jié)果。示例代碼: 1. static void
43、0;Main(string args) 2. 3. var tcs = new TaskCompletionSource<int>(); 4. &
44、#160; new Thread() => 5. Thread.Sleep(5000); 6. int i = Enu
45、merable.Range(1, 100).Sum(); 7. tcs.SetResult(i); ).Start();/線程把運(yùn)行計(jì)算結(jié)果,設(shè)為tcs的Result。 8. Task<int> tas
46、k = tcs.Task; 9. Console.WriteLine(task.Result); /此處會(huì)阻塞,直到匿名線程調(diào)用tcs.SetResult(i)完畢 10. 說(shuō)明一下以上代碼:tcs是TaskCompletionSource<int>的一個(gè)實(shí)例,即這個(gè)Task返回的肯定
47、是一個(gè)int類(lèi)型。獲得tcs的Task屬性,讀取并打印該屬性的值。那么 Console.WriteLine(task.Result);其實(shí)是會(huì)阻塞的,直到task的result被賦值之后,才會(huì)取消阻塞。而對(duì)task.result的賦值正在一個(gè)匿名線程中做的。也就是說(shuō),一直等到匿名線程運(yùn)行結(jié)束,把運(yùn)行結(jié)果賦值給tcs后,task.Result的值才會(huì)被獲得。這正是變相的實(shí)現(xiàn)了線程同步的功能,并且可以獲得線程的運(yùn)行值。而此時(shí)的線程并不是運(yùn)行在線程池上的。我們可以定義一個(gè)泛型方法,來(lái)實(shí)現(xiàn)一個(gè)Task對(duì)象,并且運(yùn)行Task的線程不是線程池線程:1. Task<TResult> R
48、un<TResult>(Func<TResult> function) 2. 3. var tcs = new TaskCompletionSource<TResult>(); 4.
49、; Thread t = new Thread() => 5. 6. try
50、160; tcs.SetResult(function(); 7. catch (Exception ex) tcs.SetException(ex); 8.
51、0; ); 9. t.IsBackground = true; 10. t.Start();/啟動(dòng)線程 11.
52、0;return tcs.Task; 12. 比如什么一個(gè)泛型方法,接受的參數(shù)是Func委托,返回的是Task類(lèi)型。該方法中啟動(dòng)一個(gè)線程t,把t設(shè)為后臺(tái)線程,該線程運(yùn)行的內(nèi)容就是傳入的Func委托,并將Func委托的運(yùn)行后的返回值通過(guò) tcs.SetResult賦給某個(gè)task。同時(shí),如果有異常的話,就把異常賦給,某個(gè)task,然后將這個(gè)task返回。這樣,直到線程運(yùn)行完畢,才 能得到task.Result的值。調(diào)用的時(shí)候: 1. Task<int&g
53、t; task = Run() => Thread.Sleep(5000); return Enumerable.Range(1, 100).Sum(); ); 2. Console.Write(task.Result);/這句會(huì)阻塞當(dāng)前線程,直到task的result值被賦值才行。 TaskCompletionSource的另一個(gè)強(qiáng)大用處,是可以創(chuàng)建Task,而不綁定任何線程,比如,我們可以通過(guò)TaskCompletionSource實(shí)現(xiàn)對(duì)某一個(gè)方法的延遲調(diào)用。代碼示例: 1. static Task<int> delayFunc()
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年雇傭合同經(jīng)典版(二篇)
- 織造工安全操作規(guī)程模版(2篇)
- 中學(xué)檔案庫(kù)房管理制度模版(3篇)
- 2024年小班下學(xué)期班務(wù)工作計(jì)劃例文(4篇)
- 實(shí)驗(yàn)室環(huán)境防護(hù)與安全制度(2篇)
- 工會(huì)職責(zé)示例校工會(huì)職責(zé)模版(2篇)
- 2024年期末演講稿范例(3篇)
- 瓦斯監(jiān)測(cè)監(jiān)控系統(tǒng)管理制度(3篇)
- 2024年人力資源助理年終工作總結(jié)模版(3篇)
- 秋冬季節(jié)安全教育
- 12J5-1 平屋面建筑標(biāo)準(zhǔn)設(shè)計(jì)圖
- 中印邊境爭(zhēng)端
- 品管圈徽SOS圈釋義
- 薩提亞模式家庭治療課件
- 行政事業(yè)單位全面實(shí)施預(yù)算績(jī)效管理思路和路徑及其評(píng)課件
- 《墨梅》課件(省一等獎(jiǎng))
- 國(guó)際貿(mào)易之進(jìn)出口流程操作課件
- 招聘與錄用期末考試卷及答案AB卷2套
- 三美術(shù)上冊(cè)第16課新穎的電腦課件1新人教版
- 實(shí)驗(yàn)室基本技能培訓(xùn)課件
- 如何申報(bào)科研項(xiàng)目 課件
評(píng)論
0/150
提交評(píng)論