多線程部分
多線程在4.0中被簡(jiǎn)化了很多,僅僅只需要用到System.Threading.Tasks.::.Task類(lèi),下面就來(lái)詳細(xì)介紹下Task類(lèi)的使用。
一、簡(jiǎn)單使用
開(kāi)啟一個(gè)線程,執(zhí)行循環(huán)方法,返回結(jié)果。開(kāi)始線程為Start(),等待線程結(jié)束為Wait()。
- ??????? /// <summary>
- ??????? /// Task簡(jiǎn)單使用
- ??????? /// </summary>
- ??????? private void Demo1()
- ??????? {
- ??????????? int i = 0;
- ??????????? Random r = new Random ( DateTime .Now.Second);
- ??????????? Task t = new Task (() =>
- ??????????? {
- ??????????????? for ( int v = 0; v < 100; v++)
- ??????????????????? i += r.Next(100);
- ??????????? });
- ??????????? t.Start();
- ??????????? t.Wait();
- ??????????? Console .WriteLine( "這是執(zhí)行Task1后等待完成:" + i.ToString());
- ??????????? Console .ReadLine();
- ??????? }
比以前使用Thread方便多了吧。
上面的例子是使用外部的變量獲得結(jié)果,下面的例子是用Task<T>直接返回結(jié)果,當(dāng)調(diào)用Result屬性時(shí),會(huì)自動(dòng)等待線程結(jié)束,等同調(diào)用了Wait()。代碼如下:
- ??????? /// <summary>
- ??????? /// Task帶返回值
- ??????? /// </summary>
- ??????? private void Demo2()
- ??????? {
- ??????????? Random r = new Random ( DateTime .Now.Second);
- ??????????? Task < int > t = new Task < int >(() =>
- ??????????? {
- ??????????????? int i = 0;
- ??????????????? for ( int v = 0; v < 100; v++)
- ??????????????????? i += r.Next(100);
- ??????????????? return i;
- ??????????? });
- ??????????? t.Start();
- ??????????? Console .WriteLine( "這是執(zhí)行Task1獲取返回值:" + t.Result.ToString());
- ??????????? Console .ReadLine();
- ??????? }
總結(jié)1:Task的使用比Thread簡(jiǎn)單很多,減少了同步,等待等等問(wèn)題,唯一的遺憾是不支持Thread的IsBackground。
結(jié)論1:如果不需要使用IsBackground,那么盡情的使用Task吧。
?
?
二、線程執(zhí)行完畢后調(diào)用另一個(gè)線程
也就是兩個(gè)線程,有序的執(zhí)行,這里使用ContinueWith(),
t執(zhí)行完畢后再執(zhí)行一個(gè)task方法,不多說(shuō)了代碼如下:
- ??????? /// <summary>
- ??????? /// Task 執(zhí)行完畢后調(diào)用另一個(gè)Task
- ??????? /// </summary>
- ??????? private void Demo3()
- ??????? {
- ??????????? Random r = new Random ( DateTime .Now.Second);
- ??????????? Task < int > t = new Task < int >(() =>
- ??????????? {
- ??????????????? int i = 0;
- ??????????????? for ( int v = 0; v < 100; v++)
- ??????????????????? i += r.Next(100);
- ??????????????? return i;
- ??????????? });
- ??????????? t.ContinueWith(( Task < int > task) =>
- ??????????? {
- ??????????????? Console .WriteLine( "這是執(zhí)行完畢Task1后繼續(xù)調(diào)用Task2:" + task.Result.ToString());
- ??????????? });
- ??????????? t.Start();
- ??????????? Console .ReadLine();
- ??????? }
也可以直接鏈?zhǔn)降膶?xiě)下去,代碼如下:
- ??????? /// <summary>
- ??????? /// Task 執(zhí)行完畢后調(diào)用另一個(gè)Task(鏈?zhǔn)綄?xiě)法)
- ??????? /// </summary>
- ??????? private void Demo4()
- ??????? {
- ??????????? Random r = new Random ( DateTime .Now.Second);
- ??????????? Task < int > t = new Task < int >(() =>
- ??????????? {
- ??????????????? int i = 0;
- ??????????????? for ( int v = 0; v < 100; v++)
- ??????????????????? i += r.Next(100);
- ??????????????? return i;
- ??????????? });
- ??????????? Task t2 = t.ContinueWith(( Task < int > task) =>
- ??????????? {
- ??????????????? Console .WriteLine(task.Result.ToString());
- ??????????? });
- ??????????? t2.ContinueWith(task =>
- ??????????? {
- ??????????????? Console .WriteLine( "這是執(zhí)行完畢Task1后繼續(xù)調(diào)用Task2,Task2后調(diào)用Task3。" );
- ??????????? });
- ??????????? t.Start();
- ??????????? Console .ReadLine();
- ??????? }
結(jié)論2:Task可以便捷的將幾個(gè)方法串行執(zhí)行。
?
?
三、帶有父子關(guān)系的線程/多線程并行開(kāi)啟
t帶有t1,t2,t3三個(gè)子線程,執(zhí)行t的時(shí)候t1,t2,t3可并行處理,t必須等待t1,t2,t3都執(zhí)行完畢后才能結(jié)束。
創(chuàng)建子Task時(shí)候必須指定參數(shù)為AttachedToParent。
- ??????? /// <summary>
- ??????? /// 帶有父子關(guān)系的Task集合,[TaskCreationOptions.AttachedToParent]
- ??????? ///
- ??????? /// 值??????????????? 說(shuō)明
- ??????? /// None????????????? 默認(rèn)值,此Task會(huì)被排入Local Queue中等待執(zhí)行,采用LIFO模式。
- ??????? /// AttachedToParent? 建立的Task必須是外圍的Task的子Task,也是放入Local Queue,採(cǎi)LIFO模式。
- ??????? /// LongRunning?????? 建立的Task不受Thread Pool所管理,直接新增一個(gè)Thread來(lái)執(zhí)行此Task,無(wú)等待、無(wú)排程。
- ??????? /// PreferFairness??? 建立的Task直接放入Global Queue中,採(cǎi)FIFO模式。(比上面的優(yōu)先級(jí)低)
- ??????? /// </summary>
- ??????? private void Demo5()
- ??????? {
- ??????????? Task < int > t = new Task < int >(() =>
- ??????????? {
- ??????????????? Task < int > t1 = new Task < int >(() =>
- ??????????????? {
- ??????????????????? int i = 0;
- ??????????????????? Random r = new Random ( DateTime .Now.Second);
- ??????????????????? for ( int v = 0; v < 100; v++)
- ??????????????????????? i += r.Next(100);
- ??????????????????? return i;
- ??????????????? }, TaskCreationOptions .AttachedToParent);
- ??????????????? Task < int > t2 = new Task < int >(() =>
- ??????????????? {
- ??????????????????? int i = 0;
- ??????????????????? Random r = new Random ( DateTime .Now.Second);
- ??????????????????? for ( int v = 0; v < 100; v++)
- ??????????????????????? i += r.Next(100);
- ??????????????????? return i;
- ??????????????? }, TaskCreationOptions .AttachedToParent);
- ??????????????? Task < int > t3 = new Task < int >(() =>
- ??????????????? {
- ??????????????????? int i = 0;
- ??????????????????? Random r = new Random ( DateTime .Now.Second);
- ??????????????????? for ( int v = 0; v < 100; v++)
- ??????????????????????? i += r.Next(100);
- ??????????????????? return i;
- ??????????????? }, TaskCreationOptions .AttachedToParent);
- ??????????????? t1.Start();
- ??????????????? t2.Start();
- ??????????????? t3.Start();
- ??????????????? return t1.Result + t2.Result + t3.Result;
- ??????????? });
- ??????????? t.Start();
- ??????????? t.Wait();
- ??????????? Console .WriteLine( "這是帶有父子關(guān)系的Task集合:" + t.Result.ToString());
- ??????????? Console .ReadLine();
- ??????? }
結(jié)論3:多個(gè)線程的同時(shí)開(kāi)啟在這里也很方便,也不用擔(dān)心同步等問(wèn)題。
?
?
四、Task的中斷
這個(gè)很復(fù)雜,就不多說(shuō)了,代碼中有比較詳細(xì)的介紹。
- ??????? /// <summary>
- ??????? /// 中途取消Task執(zhí)行,Token
- ??????? ///
- ??????? /// 一是正常結(jié)束、二是產(chǎn)生例外、三是透過(guò)Cancel機(jī)制,這三種情況都會(huì)反映在Task.Status屬性上
- ??????? /// 值????????????????????????????? 說(shuō)明
- ??????? /// Created???????????????????????? Task已經(jīng)建立,但未呼叫Start。
- ??????? /// WaitingForActivation??????????? Task已排入排程,但尚未執(zhí)行(一般我們建立的Task不會(huì)有此狀態(tài),只有ContinueWith所產(chǎn)生的Task才會(huì)有此狀態(tài))。
- ??????? /// WaitingToRun??????????????????? Task已排入排程,等待執(zhí)行中。
- ??????? /// Running???????????????????????? Task執(zhí)行中。
- ??????? /// WaitingForChildrenToComplete??? Task正等待子Task結(jié)束。
- ??????? /// RanToCompletion???????????????? Task已經(jīng)正常執(zhí)行完畢。
- ??????? /// Canceled??????????????????????? Task已被取消。
- ??????? /// Faulted???????????????????????? Task執(zhí)行中發(fā)生未預(yù)期例外。
- ??????? ///
- ??????? /// 除了Status屬性外,Task還提供了另外三個(gè)屬性來(lái)判定Task狀態(tài)。
- ??????? /// 屬性??????????? 說(shuō)明
- ??????? /// IsCompleted???? Task已經(jīng)正常執(zhí)行完畢。
- ??????? /// IsFaulted?????? Task執(zhí)行中法生未預(yù)期例外。
- ??????? /// IsCanceled????? Task已被取消。
- ??????? /// </summary>
- ??????? private void Demo6()
- ??????? {
- ??????????? CancellationTokenSource cts = new CancellationTokenSource ();
- ??????????? var ctoken = cts.Token;
- ??????????? Task t1 = new Task (() =>
- ??????????? {
- ??????????????? for ( int v = 0; v < 10; v++)
- ??????????????? {
- ??????????????????? if (ctoken.IsCancellationRequested)
- ??????????????????? {
- ??????????????????????? //第一種寫(xiě)法
- ??????????????????????? //這個(gè)會(huì)拋出異常
- ??????????????????????? ctoken.ThrowIfCancellationRequested();
- ??????????????????????? //另一種寫(xiě)法
- ??????????????????????? //這個(gè)不會(huì)返回異常,但是獲取不到是否是中斷還是執(zhí)行完畢。
- ??????????????????????? //return;
- ??????????????????? }
- ??????????????????? Thread .Sleep(1000);
- ??????????????????? Console .WriteLine(v);
- ??????????????? }
- ??????????? }, ctoken);
- ??????????? t1.Start();
- ??????????? Thread .Sleep(2000);
- ??????????? cts.Cancel();
- ??????????? try
- ??????????? {
- ??????????????? t1.Wait();
- ??????????? }
- ??????????? catch
- ??????????? {
- ??????????????? if (t1.IsCanceled)
- ??????????????????? Console .WriteLine( "cancel" );
- ??????????? }
- ??????????? Console .ReadLine();
- ??????????? cts.Dispose();
- ??????? }
結(jié)論4:中斷很復(fù)雜,但是對(duì)一般邏輯來(lái)說(shuō),是沒(méi)有很大必要的。
?
?
五、其他
這里介紹下另一種寫(xiě)法Task.Factory,以及ContinueWhenAny和ContinueWhenAll兩個(gè)方法。
Task.Factory是靜態(tài)工廠類(lèi),用于對(duì)Task提供一些麻煩的支持,這里主要介紹ContinueWhenAny和ContinueWhenAll。
ContinueWhenAll所指定的函式會(huì)在傳入的所有Tasks結(jié)束時(shí)執(zhí)行,只會(huì)執(zhí)行一次。
ContinueWhenAny所指定的函式會(huì)在傳入的Tasks中有任何一個(gè)結(jié)束時(shí)執(zhí)行,且與ContinueWhenAll相同,只會(huì)執(zhí)行一次。
好了,還是看代碼:
- ??????? /// <summary>
- ??????? /// Task.Factory
- ??????? /// ContinueWhenAny和ContinueWhenAll
- ??????? /// ContinueWhenAll所指定的函式會(huì)在傳入的所有Tasks結(jié)束時(shí)執(zhí)行,只會(huì)執(zhí)行一次。
- ??????? /// ContinueWhenAny所指定的函式會(huì)在傳入的Tasks中有任何一個(gè)結(jié)束時(shí)執(zhí)行,且與ContinueWhenAll相同,只會(huì)執(zhí)行一次。
- ??????? /// </summary>
- ??????? private void Demo7()
- ??????? {
- ??????????? Task < int > t1 = Task .Factory.StartNew< int >(() =>
- ??????????? {
- ??????????????? int total = 0;
- ??????????????? for ( int i = 0; i < 10; i++)
- ??????????????????? total += i;
- ??????????????? Thread .Sleep(12000);
- ??????????????? return total;
- ??????????? });
- ??????????? Task < int > t2 = Task .Factory.StartNew< int >(() =>
- ??????????? {
- ??????????????? int total = 0;
- ??????????????? for ( int i = 10; i < 20; i++)
- ??????????????????? total += i;
- ??????????????? Thread .Sleep(10000);
- ??????????????? return total;
- ??????????? });
- ??????????? Task tfinal = Task .Factory.ContinueWhenAny< int >(
- ???????????????????????? new Task < int >[] { t1, t2 }, ( Task < int > task) =>
- ???????????????????????? {
- ???????????????????????????? if (task.Status == TaskStatus .RanToCompletion)
- ???????????????????????????? {
- ???????????????????????????????? Console .WriteLine(task.Result);
- ???????????????????????????? }
- ???????????????????????? });
- ??????????? Console .ReadLine();
- ??????? }
結(jié)論5:ContinueWhenAny和ContinueWhenAll對(duì)特定條件執(zhí)行,還是有些用處的。
?
?
好了,這篇文章算是完結(jié)了,4.0中的并行和線程確實(shí)簡(jiǎn)單了很多,使用起來(lái)也很方便,為了性能的提升還是要適當(dāng)?shù)氖褂孟隆?
謝謝觀賞
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
