然而镇饺,在今天這篇博客中匙睹,我們要知道的是,QueueUserWorkItem這個技術存在許多限制瑟由。其中最大的問題是沒有一個內(nèi)建的機制讓你知道操作在什么時候完成絮重,也沒有一個機制在操作完成是獲得一個返回值,這些問題使得我們都不敢啟用這個技術。
Microsoft為了克服這些限制(同時解決其他一些問題)青伤,引入了任務(tasks)的概念督怜。順帶說一下我們得通過System.Threading.Tasks命名空間來使用它們。
現(xiàn)在我要說的是狠角,用線程池不是調(diào)用ThreadPool的QueueUserWorkItem方法号杠,而是用任務來做相同的事:
復制代碼 1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? ? ? ? ? ? Console.WriteLine("主線程啟動");?
4? ? ? ? ? ? //ThreadPool.QueueUserWorkItem(StartCode,5);?
5? ? ? ? ? ? new Task(StartCode, 5).Start();
?6? ? ? ? ? ? Console.WriteLine("主線程運行到此!");?
7? ? ? ? ? ? Thread.Sleep(1000);?
8? ? ? ? }?
9 10? ? ? ? private static void StartCode(object i)
11? ? ? ? {
12? ? ? ? ? ? Console.WriteLine("開始執(zhí)行子線程...{0}",i);
13? ? ? ? ? ? Thread.Sleep(1000);//模擬代碼操作? ?
?14? ? ? ? }
15? ? }
嘿丰歌,你會發(fā)現(xiàn)結果是一樣的姨蟋。再來看看這個是什么:TaskCreationOptions這個類型是一個枚舉類型,傳遞一些標志來控制Task的執(zhí)行方式立帖。TaskCreationOptions定義如下:慢點眼溶,注釋很詳細,看看這些有好處晓勇,TaskScheduler(任務調(diào)度器)不懂沒關系堂飞,請繼續(xù)往下看,我會介紹的绑咱,但請注意绰筛,這些標識都只是一些提議而已,在調(diào)度一個Task時羡玛,可能會、也可能不會采納這些提議宗苍,不過有一條要注意:AttachedToParent標志稼稿,它總會得到Task采納,因為它和TaskScheduler本身無關讳窟。
來看下這段代碼:
1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? ? ? ? ? ??
? 4? ? ? ? ? ? //1000000000這個數(shù)字會拋出System.AggregateException?
5??
6? ? ? ? ? ? Taskt = new Task(n => Sum((Int32)n), 1000000000);?
7?
?8? ? ? ? ? ? //可以現(xiàn)在開始让歼,也可以以后開始??
9 10? ? ? ? ? ? t.Start();
11 12? ? ? ? ? ? //Wait顯式的等待一個線程完成
13 14? ? ? ? ? ? t.Wait();
15? ? ? ? ? ? 16? ? ? ? ? ? Console.WriteLine("The Sum is:"+t.Result);
17? ? ? ? }
18 19? ? ? ? private static Int32 Sum(Int32 i)
20? ? ? ? {
21? ? ? ? ? ? Int32 sum = 0;
22? ? ? ? ? ? for (; i > 0; i--)
23? ? ? ? ? ? ? ? checked { sum += i; }
24? ? ? ? ? ? return sum;
25? ? ? ? }
26? ? }
這段代碼大家應該猜得出是什么意思吧,人人都會寫丽啡∧庇遥 但是,我的結果為什么是t.Result而不直接是返回的Sum呢补箍?? 有沒有多此一舉的感覺改执?下面我來說說這段代碼我想表達的意思: 在一個線程調(diào)用Wait方法時,系統(tǒng)會檢查線程要等待的Task是否已經(jīng)開始執(zhí)行坑雅,如果任務正在執(zhí)行辈挂,那么這個Wait方法會使線程阻塞,知道Task運行結束為止裹粤≈盏伲 就說上面的程序執(zhí)行,因為累加數(shù)字太大,它拋出算術運算溢出錯誤拇泣,在一個計算限制任務拋出一個未處理的異常時噪叙,這個異常會被“包含”不并存儲到一個集合中,而線程池線程是允許返回到線程池中的霉翔,在調(diào)用Wait方法或者Result屬性時睁蕾,這個成員會拋出一個System.AggregateException對象≡绻辏 現(xiàn)在你會問惫霸,為什么要調(diào)用Wait或者Result?或者一直不查詢Task的Exception屬性葱弟?你的代碼就永遠注意不到這個異常的發(fā)生壹店,如果不能捕捉到這個異常,垃圾回收時芝加,拋出AggregateException冯乘,進程就會立即終止兰绣,這就是“牽一發(fā)動全身”,莫名其妙程序就自己關掉了,誰也不知道這是什么情況效扫。所以,必須調(diào)用前面提到的某個成員莉恼,確保代碼注意到異常咕村,并從異常中恢復。悄悄告訴你来吩,其實在用Result的時候敢辩,內(nèi)部會調(diào)用Wait〉芙 怎么恢復戚长? 為了幫助你檢測沒有注意到的異常,可以向TaskScheduler的靜態(tài)UnobservedTaskException時間等級一個回調(diào)方法怠苔,當Task被垃圾回收時同廉,如果出現(xiàn)一個沒有被注意到的異常,CLR終結器會引發(fā)這個事件柑司。一旦引發(fā)迫肖,就會向你的時間處理器方法傳遞一個UnobservedTaskExceptionEvenArgs對象,其中包含了你沒有注意的AggregateException攒驰。然后再調(diào)用UnobservedTasExceptionEvenArgs的SetObserved方法來指出你的異常已經(jīng)處理好了咒程,從而阻止CLR終止進程。這是個圖省事的做法讼育,要少做這些帐姻,寧愿終止進程稠集,也不要呆著已經(jīng)損壞的狀態(tài)而繼續(xù)運行。做人也一樣饥瓷,病了寧肯休息剥纷,也不要帶病堅持上班,你沒那么偉大呢铆,公司也不需要你的這一點偉大,命是自己的晦鞋。(─.─|||扯遠了」卓耍 除了單個等待任務悠垛,Task 還提供了兩個靜態(tài)方法:WaitAny和WaitAll,他們允許線程等待一個Task對象數(shù)組娜谊∪仿颍 WaitAny方法會阻塞調(diào)用線程,知道數(shù)組中的任何一個Task對象完成纱皆,這個方法會返回一個索引值湾趾,指明完成的是哪一個Task對象。如果發(fā)生超時派草,方法將返回-1搀缠。它可以通過一個CancellationToken取消,會拋出一個OperationCanceledException近迁∫掌眨 WaitAll方法也會阻塞調(diào)用線程,知道數(shù)組中的所有Task對象都完成鉴竭,如果全部完成就返回true歧譬,如果超時就返回false。當然它也能取消拓瞪,同樣會拋出OperationCanceledException缴罗≈觯 說了這么兩個取消任務的方法祭埂,現(xiàn)在來試試這個方法,加深下印象兵钮,修改先前例子代碼蛆橡,完整代碼如下:
?1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? ? ? ? ? ? CancellationTokenSource cts = new CancellationTokenSource();
?4? ? ? ? ? ??
? 5? ? ? ? ? ? ??
6? 7? ? ? ? ? ? Taskt = new Task(() => Sum(cts.Token,10000), cts.Token);?
8? 9? ? ? ? ? ? //可以現(xiàn)在開始,也可以以后開始?
10? ? ? ? ? ? 11? ? ? ? ? ? t.Start();
12 13? ? ? ? ? ? //在之后的某個時間掘譬,取消CancellationTokenSource 以取消Task
14 15? ? ? ? ? ? cts.Cancel();//這是個異步請求泰演,Task可能已經(jīng)完成了。我是雙核機器葱轩,Task沒有完成過
16 17 18? ? ? ? ? ? //注釋這個為了測試拋出的異常
19? ? ? ? ? ? //Console.WriteLine("This sum is:" + t.Result);
20? ? ? ? ? ? try
21? ? ? ? ? ? {
22? ? ? ? ? ? ? ? //如果任務已經(jīng)取消了睦焕,Result會拋出AggregateException
23 24? ? ? ? ? ? ? ? Console.WriteLine("This sum is:" + t.Result);
25? ? ? ? ? ? }
26? ? ? ? ? ? catch (AggregateException x)
27? ? ? ? ? ? {
28? ? ? ? ? ? ? ? //將任何OperationCanceledException對象都視為已處理藐握。
29? ? ? ? ? ? ? ? //其他任何異常都造成拋出一個AggregateException,其中
30? ? ? ? ? ? ? ? //只包含未處理的異常
31 32? ? ? ? ? ? ? ? x.Handle(e => e is OperationCanceledException);
33? ? ? ? ? ? ? ? Console.WriteLine("Sum was Canceled");
34? ? ? ? ? ? }
35? ? ? ? ? 36? ? ? ? }
37 38? ? ? ? private static Int32 Sum(CancellationToken ct ,Int32 i)
39? ? ? ? {
40? ? ? ? ? ? Int32 sum = 0;
41? ? ? ? ? ? for (; i > 0; i--)
42? ? ? ? ? ? {
43? ? ? ? ? ? ? ? //在取消標志引用的CancellationTokenSource上如果調(diào)用
44? ? ? ? ? ? ? ? //Cancel垃喊,下面這一行就會拋出OperationCanceledException
45 46? ? ? ? ? ? ? ? ct.ThrowIfCancellationRequested();
47 48? ? ? ? ? ? ? ? checked { sum += i; }
49? ? ? ? ? ? }
50? ? ? ? ? ? 51? ? ? ? ? ? return sum;
52? ? ? ? }
53? ? }
這個例子展示了一個任務在進行的時候中途取消的操作猾普,我覺得它很有趣,你試試也會發(fā)現(xiàn)本谜〕跫遥 Lamada表達式寫這個,是個亮點乌助,得學學溜在,將CancellationToken閉包變量“傳遞”。
如果不用Lamada表達式他托,這問題還真不好解決: Taskt = new Task(() => Sum(cts.Token,10000), cts.Token); Sum(cts.Token,10000) 內(nèi)的Token需要和cts.Token關聯(lián)起來掖肋,你還能想出怎么關聯(lián)起來么?
好上祈,任務取消也講玩了培遵,來看個更好用的技術:
1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? 4? ? ? ? ? ? Taskt = new Task(i => Sum((Int32)i),10000);?
5? 6? ? ? ? ? ? //可以現(xiàn)在開始,也可以以后開始??
7? ? ? ? ? ? ? 8? ? ? ? ? ? t.Start();?
9 10? ? ? ? ? ? Task cwt =? t.ContinueWith(task=>Console.WriteLine("The sum is:{0}",task.Result));
11? ? ? ? ? ? cwt.Wait();
12? ? ? ? ? ? 13? ? ? ? }
14 15? ? ? ? private static Int32 Sum(Int32 i)
16? ? ? ? {
17? ? ? ? ? ? Int32 sum = 0;
18? ? ? ? ? ? for (; i > 0; i--)
19? ? ? ? ? ? {
20? ? ? ? ? ? ? ? checked { sum += i; }
21? ? ? ? ? ? }
22? ? ? ? ? ? 23? ? ? ? ? ? return sum;
24? ? ? ? }
25? ? }
ContinueWith登刺?? 啥東西~~籽腕?? 要寫可伸縮的軟件纸俭,一定不能使你的線程阻塞皇耗。這意味著如果調(diào)用Wait或者在任務未完成時查詢Result屬性,極有可能造成線程池創(chuàng)建一個新線程揍很,這增大了資源的消耗郎楼,并損害了伸縮性≈匣冢 ContinueWith便是一個更好的方式呜袁,一個任務完成時它可以啟動另一個任務。上面的例子不會阻塞任何線程简珠。
當Sum的任務完成時阶界,這個任務會啟動另一個任務以顯示結果。ContinueWith會返回對新的Task對象的一個引用聋庵,所以為了看到結果膘融,我需要調(diào)用一下Wait方法,當然你也可以查詢下Result祭玉,或者繼續(xù)ContinueWith氧映,返回的這個對象可以忽略,它僅僅是一個變量脱货〉憾迹 還要指出的是律姨,Task對象內(nèi)部包含了ContinueWith任務的一個集合。所以臼疫,實際上可以用一個Task對象來多次調(diào)用ContinueWith线召。任務完成時,所有ContinueWith任務都會進入線程池隊列中多矮,在構造ContinueWith的時候我們可以看到一個TaskContinuationOptions枚舉值缓淹,不能忽視,看看它的定義:PrefereFairness是盡量公平的意思塔逃,就是較早調(diào)度的任務可能較早的運行讯壶,先來后到,將線程放到全局隊列湾盗,便可以實現(xiàn)這個效果伏蚊。ExecuteSynchronously指同步執(zhí)行,強制兩個任務用同一個線程一前一后運行格粪,然后就同步運行了躏吊。 看得是不是暈乎乎 ?有這么多枚舉例子帐萎,怎么掌握氨确?多看幾次疆导,知道任務的使用情況赁项,以后用起來得心應手~想學新技術,就要能耐住澈段,才能基礎牢固悠菜。來看個例子,用用這些枚舉败富。
?1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? ? ? ? ? ? Taskt = new Task(i => Sum((Int32)i),10000);?
4? 5? ? ? ? ? ? t.Start();?
6? 7? ? ? ? ? ? t.ContinueWith(task=>Console.WriteLine("The sum is:{0}",task.Result), 8? ? ? ? ? ? ? ? TaskContinuationOptions.OnlyOnRanToCompletion);?
9? ? ? ? ? ? 10? ? ? ? ? ? t.ContinueWith(task=>Console.WriteLine("Sum throw:"+task.Exception),11? ? ? ? ? ? ? ? TaskContinuationOptions.OnlyOnFaulted);
12? ? ? ? ? ? 13? ? ? ? ? ? t.ContinueWith(task=>Console.WriteLine("Sum was cancel:"+task.IsCanceled),14? ? ? ? ? ? ? ? TaskContinuationOptions.OnlyOnCanceled);
15? ? ? ? ? ? try
16? ? ? ? ? ? {
17? ? ? ? ? ? ? ? t.Wait();? // 測試用
18? ? ? ? ? ? }
19? ? ? ? ? ? catch (AggregateException)
20? ? ? ? ? ? {
21? ? ? ? ? ? ? ? Console.WriteLine("出錯");
22? ? ? ? ? ? }
23? ? ? ? ? ? 24? ? ? ? ? ? 25? ? ? ? }
26 27? ? ? ? private static Int32 Sum(Int32 i)
28? ? ? ? {
29? ? ? ? ? ? Int32 sum = 0;
30? ? ? ? ? ? for (; i > 0; i--)
31? ? ? ? ? ? {
32? ? ? ? ? ? ? ? checked { sum += i; }
33? ? ? ? ? ? }
34? ? ? ? ? ? 35? ? ? ? ? ? return sum;
36? ? ? ? }
37? ? }
ContinueWith講完了悔醋。可是還沒有結束哦兽叮》医荆 AttachedToParnt枚舉類型(父任務)也不能放過!看看怎么用充择,寫法有點新奇德玫,看看:?
?1? ? ? ? static void Main(string[] args)?
2? ? ? ? {?
3? ? ? ? ? ? Taskparent = new Task(() => {
?4? ? ? ? ? ? ? ? var results = new Int32[3];?
5? ? ? ? ? ? ? ? //
?6? ? ? ? ? ? ? ? new Task(() => results[0] = Sum(10000), TaskCreationOptions.AttachedToParent).Start();?
7? ? ? ? ? ? ? ? new Task(() => results[1] = Sum(20000), TaskCreationOptions.AttachedToParent).Start();?
8? ? ? ? ? ? ? ? new Task(() => results[2] = Sum(30000), TaskCreationOptions.AttachedToParent).Start();?
9? ? ? ? ? ? ? ? return results;
10? ? ? ? ? ? });
11 12? ? ? ? ? ? var cwt = parent.ContinueWith( parentTask=>Array.ForEach(parentTask.Result,Console.WriteLine));
13? ? ? ? ? ? ? ? ? ? 14 15? ? ? ? ? ? parent.Start();
16? ? ? ? ? ? cwt.Wait();
17? ? ? ? }
18 19? ? ? ? private static Int32 Sum(Int32 i)
20? ? ? ? {
21? ? ? ? ? ? Int32 sum = 0;
22? ? ? ? ? ? for (; i > 0; i--)
23? ? ? ? ? ? {
24? ? ? ? ? ? ? ? checked { sum += i; }
25? ? ? ? ? ? }
26? ? ? ? ? ? return sum;
27? ? ? ? }
28? ? }復制代碼Oh匪蟀,我都寫暈了椎麦。。材彪。(+﹏+)~例子中观挎,父任務創(chuàng)建兵啟動3個Task對象琴儿。默認情況下,一個任務創(chuàng)建的Task對象是頂級任務嘁捷,這些任務跟創(chuàng)建它們的那個任務沒有關系造成。TaskCreationOptions.AttachedToParent標志將一個Task和創(chuàng)建它的那個Task關聯(lián)起來,除非所有子任務(子任務的子任務)結束運行雄嚣,否則創(chuàng)建任務(父任務)不會認為已經(jīng)結束晒屎。調(diào)用ContinueWith方法創(chuàng)建一個Task時,可以指定TaskContinuationOptions.AttachedToParent標志將延續(xù)任務置頂為一個子任務缓升。
看了這么多任務的方法操作示例了鼓鲁,現(xiàn)在來挖挖任務內(nèi)部構造: 每個Task對象都有一組構成任務狀態(tài)的字段「垡辏 一個Int32 ID(只讀屬性)代表Task執(zhí)行狀態(tài)的一個Int32對父任務的一個引用對Task創(chuàng)建時置頂TaskSchedule的一個引用對回調(diào)方法的一個引用對要傳給回調(diào)方法的對象的一個引用(通過Task只讀AsyncState屬性查詢)對一個ExceptionContext的引用對一個ManualResetEventSlim對象的引用還有沒個Task對象都有對根據(jù)需要創(chuàng)建的一些補充狀態(tài)的一個引用骇吭,補充狀態(tài)包含這些:一個CancellationToken一個ContinueWithTask對象集合為拋出未處理異常的子任務,所準備的一個Task對象集合說了這么多歧寺,只想要大家知道:
雖然任務提供了大量功能燥狰,但并不是沒有代價的。因為必須為所有的這些狀態(tài)分配內(nèi)存斜筐。如果不需要任務提供的附加功能龙致,使用ThreadPool.QueueUserWorkItem,資源的使用效率會更高一些顷链。Task類還實現(xiàn)了IDispose接口净当,允許你在用完Task對象后調(diào)用Dispose,不過大多數(shù)不管蕴潦,讓垃圾回收器回收就好像啼。創(chuàng)建一個Task對象時,代表Task唯一的一個Int32字段初始化為零潭苞,TaskID從1開始忽冻,每分配一個ID都遞增1。順帶說一下此疹,在你調(diào)試中查看一個Task對象的時候僧诚,會造成調(diào)試器顯示Task的ID,從而造成為Task分配一個ID蝗碎『浚 這個ID的意義在于,每個Task都可以用一個唯一的值來標識蹦骑。Visual Studio會在它的“并行任務”和并行堆棿仁。“窗口中顯示這些任務ID。要知道的是眠菇,這是Visual Studio自己分配的ID边败,不是在自己代碼中分配的ID袱衷,幾乎不可能將Visual Studio分配的ID和代碼正在做的事情聯(lián)系起來。要查看自己正在運行的任務笑窜,可以在調(diào)試的時候查看Task的靜態(tài)CurrentId屬性致燥,如果沒有任務在執(zhí)行,CurrentId返回null排截∠釉椋 再看看TaskStatus的值,這個可以查詢Task對象的生存期:這些在任務運行的時候都是可以一一查到的断傲,還有~判斷要像這樣:1 if(task.Status==TaskStatus.RantoCompletion)...為了簡化編碼,Task只提供幾個只讀Boolean屬性:IsCanceled搬葬,IsFaulted,IsCompleted艳悔,它們能返回最終狀態(tài)true/false急凰。如果Task是通過調(diào)用某個函數(shù)來創(chuàng)建的,這個Task對象就會出于WaitingForActivation狀態(tài)猜年,它會自動運行抡锈。最后我們要來了解一下TaskFactory(任務工廠):
1.需要創(chuàng)建一組Task對象來共享相同的狀態(tài)
2.為了避免機械的將相同的參數(shù)傳給每一個Task的構造器。滿足這些條件就可以創(chuàng)建一個任務工廠來封裝通用的狀態(tài)乔外。TaskFactory類型和TaskFactory類型床三,它們都派生System.Object。你會學到不一樣的編碼方式:復制代碼 1? ? ? ? static void Main(string[] args) 2? ? ? ? {?
3? ? ? ? ? ? Task parent = new Task(() =>?
4? ? ? ? ? ? {?
5? ? ? ? ? ? ? ? var cts = new CancellationTokenSource();?
6? ? ? ? ? ? ? ? var tf = new TaskFactory(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
7
8? ? ? ? ? ? ? ? //創(chuàng)建并啟動3個子任務
9? ? ? ? ? ? ? ? var childTasks = new[] {
10? ? ? ? ? ? tf.StartNew(() => Sum(cts.Token, 10000)),
11? ? ? ? ? ? tf.StartNew(() => Sum(cts.Token, 20000)),
12? ? ? ? ? ? tf.StartNew(() => Sum(cts.Token, Int32.MaxValue))? // 這個會拋異常
13? ? ? ? ? };
14
15? ? ? ? ? ? ? ? // 任何子任務拋出異常就取消其余子任務
16? ? ? ? ? ? ? ? for (Int32 task = 0; task < childTasks.Length; task++)
17? ? ? ? ? ? ? ? ? ? childTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);
18
19? ? ? ? ? ? ? ? // 所有子任務完成后杨幼,從未出錯/未取消的任務獲取返回的最大值
20? ? ? ? ? ? ? ? // 然后將最大值傳給另一個任務來顯示最大結果
21? ? ? ? ? ? ? ? tf.ContinueWhenAll(childTasks,
22? ? ? ? ? ? ? ? ? ? completedTasks => completedTasks.Where(t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result),
23? ? ? ? ? ? ? ? ? ? CancellationToken.None)
24? ? ? ? ? ? ? ? ? ? .ContinueWith(t => Console.WriteLine("The maxinum is: " + t.Result),
25? ? ? ? ? ? ? ? ? ? ? TaskContinuationOptions.ExecuteSynchronously).Wait(); // Wait用于測試
26? ? ? ? ? ? });
27
28? ? ? ? ? ? // 子任務完成后撇簿,也顯示任何未處理的異常
29? ? ? ? ? ? parent.ContinueWith(p =>
30? ? ? ? ? ? {
31? ? ? ? ? ? ? ? // 用StringBuilder輸出所有
32
33? ? ? ? ? ? ? ? StringBuilder sb = new StringBuilder("The following exception(s) occurred:" + Environment.NewLine);
34? ? ? ? ? ? ? ? foreach (var e in p.Exception.Flatten().InnerExceptions)
35? ? ? ? ? ? ? ? ? ? sb.AppendLine("? " + e.GetType().ToString());
36? ? ? ? ? ? ? ? Console.WriteLine(sb.ToString());
37? ? ? ? ? ? }, TaskContinuationOptions.OnlyOnFaulted);
38
39? ? ? ? ? ? // 啟動父任務
40? ? ? ? ? ? parent.Start();
41
42? ? ? ? ? ? try
43? ? ? ? ? ? {
44? ? ? ? ? ? ? ? parent.Wait(); //顯示結果
45? ? ? ? ? ? }
46? ? ? ? ? ? catch (AggregateException)
47? ? ? ? ? ? {
48? ? ? ? ? ? }
49? ? ? ? }
50
51? ? ? ? private static Int32 Sum(CancellationToken ct, Int32 n)
52? ? ? ? {
53? ? ? ? ? ? Int32 sum = 0;
54? ? ? ? ? ? for (; n > 0; n--)
55? ? ? ? ? ? {
56? ? ? ? ? ? ? ? ct.ThrowIfCancellationRequested();
57? ? ? ? ? ? ? ? checked { sum += n; }
58? ? ? ? ? ? }
59? ? ? ? ? ? return sum;
60? ? ? ? }
61? ? }
復制代碼
任務工廠就這么用,就是一個任務的集合差购。
現(xiàn)在看看TaskScheduler(任務調(diào)度)
任務基礎結構是很靈活的四瘫,TaskScheduler對象功不可沒。
TaskScheduler對象負責執(zhí)行調(diào)度的任務欲逃,同時向Visual Studio調(diào)試器公開任務信息找蜜,就像一座橋梁,讓我們能夠掌控自己的任務線程稳析。
TaskScheduler有兩個派生類:thread pool task scheduler(線程池任務調(diào)度)洗做,和synchronization context task scheduler(同步上下文任務調(diào)度器)。默認情況下彰居,所以應用程序使用的都是線程池任務調(diào)度器诚纸,這個任務調(diào)度器將任務調(diào)度給線程池的工作者線程〕露瑁可以查詢TaskScheduler的靜態(tài)Default屬性來獲得對默認任務調(diào)度器的一個引用畦徘。
同步上下文任務調(diào)度器通常用于桌面應用程序,Winfrom,WPF及Silverlight旧烧。這個任務調(diào)度器將多有任務都調(diào)度給應用程序的GUI線程,使所有任務代碼都能成功更新UI組建画髓,比如按鈕掘剪、菜單項等。同步上下文任務調(diào)度器根本不使用線程池奈虾。同樣夺谁,可以查詢TaskScheduler的靜態(tài)FromCurrentSynchronizationContext方法來獲得對一個同步上下文任務調(diào)度器的引用。
就像這樣創(chuàng)建類型:
1 //同步上下文任務調(diào)度
2 TaskScheduler m_syncContextTaskScheduler =
3? ? ? ? ? ? TaskScheduler.FromCurrentSynchronizationContext();
任務調(diào)度有很多的肉微,下面列舉一部分匾鸥,供參考,更多的請參看http://code.msdn.microsoft.com/ParExtSamples? 它包括了大量的示例代碼碉纳。