最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#多線程學(xué)習(xí)之Thread、ThreadPool、Task、Parallel四者區(qū)別

 更新時(shí)間:2021年12月17日 08:39:24   作者:Alan.hsiang  
這篇文章主要以一些簡(jiǎn)單的小例子,簡(jiǎn)述多線程的發(fā)展歷程:Thread,ThreadPool,Task,Parallel。文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#多線程有一定幫助,需要的朋友可以參考一下

線程(英語(yǔ):thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)。進(jìn)程是資源分配的基本單位。所有與該進(jìn)程有關(guān)的資源,都被記錄在進(jìn)程控制塊PCB中。以表示該進(jìn)程擁有這些資源或正在使用它們。本文以一些簡(jiǎn)單的小例子,簡(jiǎn)述多線程的發(fā)展歷程【Thread,ThreadPool,Task,Parallel】,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。

Thread

Thread做為早期【.Net Framework1.0】的.Net提供的多線程方案,提供了很多的封裝方法,來(lái)操作線程。具體如下所示:

  1. Start方法,用于啟動(dòng)一個(gè)線程。線程的狀態(tài)變更為Running。
  2. Suspend方法,掛起一個(gè)線程,或者如果線程狀態(tài)為已掛起,則不起作用。
  3. Resume方法,如果線程為已掛起,這繼續(xù)運(yùn)行。
  4. Join方法,等待線程,直到線程結(jié)束,也可以設(shè)置等待時(shí)間。
  5. Abort方法,強(qiáng)制終止線程,跑出ThreadAbortException異常。
  6. 其他線程屬性:IsBackground是否后臺(tái)線程,IsThreadPoolThread是否線程池線程,IsAlive線程是否運(yùn)行,Priority線程優(yōu)先級(jí),ThreadState當(dāng)前線程狀態(tài),ManagedThreadId線程唯一標(biāo)識(shí)等

通過(guò)Thread可以單獨(dú)的開啟一個(gè)線程,通過(guò)構(gòu)造函數(shù)來(lái)創(chuàng)建線程對(duì)象,可以是無(wú)參數(shù)也可以是帶參數(shù)。其中參數(shù)ThreadStart是一個(gè)無(wú)參數(shù)委托,ParameterizedThreadStart為一個(gè)帶參數(shù)委托。

無(wú)參數(shù),示例如下所示:

private void btnThread_Click(object sender, EventArgs e)
{
    ThreadStart threadStart = new ThreadStart(DoSomethingLong);
    Thread thread = new Thread(threadStart);
    thread.Start();
}

private void DoSomethingLong() {
    string name = "Thread";
    Console.WriteLine("************DoSomethingLong 開始 name= {0} 線程ID= {1} 時(shí)間 = {2}************", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
    //CPU計(jì)算累加和
    long rest = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        rest += i;
    }
    Console.WriteLine("************DoSomethingLong 結(jié)束 name= {0} 線程ID= {1} 時(shí)間 = {2} 結(jié)果={3}************", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), rest);
}

示例結(jié)果如下所示:

帶參數(shù)示例,如下所示:

private void btnThread2_Click(object sender, EventArgs e)
{
    ParameterizedThreadStart threadStart = new ParameterizedThreadStart(DoSomethingLongWithParam);
    Thread thread = new Thread(threadStart);
    string name = "Param";
    thread.Start(name);
}

private void DoSomethingLongWithParam(object name) {
    Console.WriteLine("************DoSomethingLongWithParam 開始 name= {0} 線程ID= {1} 時(shí)間 = {2}************", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
    //CPU計(jì)算累加和
    long rest = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        rest += i;
    }
    Console.WriteLine("************DoSomethingLongWithParam 結(jié)束 name= {0} 線程ID= {1} 時(shí)間 = {2} 結(jié)果={3}************", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), rest);
}

帶參數(shù)示例結(jié)果,如下所示:

通過(guò)對(duì)以上示例進(jìn)行分析,得出結(jié)論如下所示:

  1. 線程是由操作系統(tǒng)進(jìn)行創(chuàng)建的,Thread提供的方法只是對(duì)底層方法的封裝。比如執(zhí)行對(duì)應(yīng)方法后,操作系統(tǒng)并不會(huì)立即執(zhí)行相應(yīng)的操作,而要CPU時(shí)間片輪轉(zhuǎn)后才會(huì)執(zhí)行響應(yīng)。
  2. Thread創(chuàng)建線程過(guò)于松散,缺乏管理,例如,如果同時(shí)創(chuàng)建10000個(gè)線程,程序也不會(huì)報(bào)錯(cuò),但是系統(tǒng)可能無(wú)法承載如此多的線程而導(dǎo)致崩潰。
  3. Thread的頻繁創(chuàng)建和銷毀,也會(huì)消耗系統(tǒng)資源。

ThreadPool

為了應(yīng)對(duì)Thread創(chuàng)建缺乏管理的問(wèn)題,在后續(xù)版本【.Net Framework2.0】中推出了線程池的概念。那什么是線程池呢?

池化資源管理設(shè)計(jì)思想:線程是一種資源,之前每次需要線程,都是去創(chuàng)建線程,使用完成后,再釋放掉。池化,就是做一個(gè)容器,容器提前申請(qǐng)指定數(shù)量的線程,需要用到線程的時(shí)候,直接到線程池中取,用完之后再放回容器【通過(guò)控制狀態(tài)標(biāo)識(shí)線程是否正在被使用】。避免頻繁的創(chuàng)建和銷毀,容器還會(huì)根據(jù)限制的數(shù)量取申請(qǐng)和釋放。

關(guān)于通過(guò)線程池創(chuàng)建多線程,具體示例如下:

private void btnThread3_Click(object sender, EventArgs e)
 {
    WaitCallback waitCallback = new WaitCallback(DoSomethingLongWithParam);
     string name = "ThreadPool";
     ThreadPool.QueueUserWorkItem(waitCallback,name);
 }

線程池示例執(zhí)行結(jié)果如下所示:

通過(guò)對(duì)線程池執(zhí)行結(jié)果進(jìn)行分析,得出結(jié)論如下:

  1. 兩次執(zhí)行結(jié)果,均為同一個(gè)線程ID,說(shuō)明線程用完并未銷毀,而是放回線程池子,待下次使用時(shí)重新取出,繼續(xù)使用。
  2. 通過(guò)線程池可以有效的控制線程并發(fā)的數(shù)量,避免資源的浪費(fèi)。
  3. 通過(guò)分析源碼發(fā)現(xiàn),ThreadPool線程池提供的接口較少,在線程等待和交互方面不太友好。

Task

隨著.Net版本的演化,后續(xù)版本【.Net Framework3.0】推出了Task做為多線程解決方案。默認(rèn)情況下,可以通過(guò)構(gòu)造函數(shù)創(chuàng)建Task,示例如下:

private void btnTask_Click(object sender, EventArgs e)
 {
     Action action = new Action(DoSomethingLong);
     Task task = new Task(action);
     task.Start();
 }

默認(rèn)Task示例,執(zhí)行結(jié)果如下:

通過(guò)對(duì)以上Task示例和源碼進(jìn)行分析,得出結(jié)論如下:

  1. Task產(chǎn)生的線程,全部都是線程池線程。
  2. Task提供的豐富的API,便于開發(fā)實(shí)踐。

Parallel

Parallel提供對(duì)并行線程的支持,可以通過(guò)Parallel同時(shí)發(fā)起多個(gè)線程,在某些方面具有應(yīng)用優(yōu)勢(shì),默認(rèn)示例如下所示:

 private void btnParallel_Click(object sender, EventArgs e)
 {
     Action action = new Action(DoSomethingLong);
     Parallel.Invoke(action,action,action);
 }

Parallel的Invoke方法執(zhí)行,結(jié)果如下:

通過(guò)對(duì)Parallel的Invoke示例方法進(jìn)行分析,得出結(jié)論如下:

  1. Parallel的Invoke方法,可以同時(shí)開啟多個(gè)線程,同時(shí)主線程【線程ID=1】也會(huì)參與計(jì)算,即頁(yè)面也會(huì)卡住。
  2. Parallel可以通過(guò)ParallelOptions.MaxDegreeOfParallelism指定并發(fā)數(shù)量。

Task專講

以下面的一個(gè)場(chǎng)景為例進(jìn)行說(shuō)明:

假如開發(fā)一個(gè)系統(tǒng),流程如下:

1. 前期的需求調(diào)研,需求分析,系統(tǒng)設(shè)計(jì),詳細(xì)設(shè)計(jì)(順序執(zhí)行,是開發(fā)編碼的前提)

2.按模塊開發(fā)【中間階段,可多人同時(shí)工作】

3.測(cè)試【順序執(zhí)行,是開發(fā)編碼的后續(xù)工作】

分析:以上三個(gè)階段,每一個(gè)階段又可以細(xì)分?jǐn)?shù)個(gè)小階段,其中有些階段是順序執(zhí)行的,有些階段又可以并行執(zhí)行。

以代碼的形式進(jìn)行描述,如下所示:

private void btnTask2_Click(object sender, EventArgs e)
{
    //開發(fā)前的工作
    Console.WriteLine("組建團(tuán)隊(duì)");
    Console.WriteLine("需求分析");
    Console.WriteLine("系統(tǒng)設(shè)計(jì)");
    Console.WriteLine("詳細(xì)設(shè)計(jì)");
    //開始開發(fā)
    Task.Run(() => { Coding("張三", "接口"); });
    Task.Run(() => { Coding("李四", "前端頁(yè)面"); });
    Task.Run(() => { Coding("王五", "手機(jī)App"); });
    Task.Run(() => { Coding("劉大", "后端業(yè)務(wù)"); });
    //開發(fā)后的工作
    Console.WriteLine("alpha測(cè)試");
    Console.WriteLine("beta測(cè)試");
    Console.WriteLine("uat測(cè)試");
    Console.WriteLine("系統(tǒng)上線");
}

private void Coding(string developer,string model) {
    Console.WriteLine("【Begin】在{0},{1}開始開發(fā){2},線程id為{3}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), developer,model, Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1000);
    Console.WriteLine("【 End 】在{0},{1}完成開發(fā){2},線程id為{3}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), developer, model, Thread.CurrentThread.ManagedThreadId);
}

示例運(yùn)行結(jié)果,如下所示:

通過(guò)分析以上示例,發(fā)現(xiàn)程序并未按照預(yù)期的運(yùn)行,很明顯的一點(diǎn):測(cè)試跑到了開發(fā)前面。

為了解決上述順序錯(cuò)亂的問(wèn)題,Task提供了WaitAll方法,如下所示:

private void btnTask2_Click(object sender, EventArgs e)
{
    //開發(fā)前的工作
    Console.WriteLine("組建團(tuán)隊(duì)");
    Console.WriteLine("需求分析");
    Console.WriteLine("系統(tǒng)設(shè)計(jì)");
    Console.WriteLine("詳細(xì)設(shè)計(jì)");
    //開始開發(fā)
    List<Task> tasks = new List<Task>();
    tasks.Add(Task.Run(() => { Coding("張三", "接口"); }));
    tasks.Add(Task.Run(() => { Coding("李四", "前端頁(yè)面"); }));
    tasks.Add(Task.Run(() => { Coding("王五", "手機(jī)App"); }));
    tasks.Add(Task.Run(() => { Coding("劉大", "后端業(yè)務(wù)"); }));
    Task.WaitAll(tasks.ToArray());
    //開發(fā)后的工作
    Console.WriteLine("alpha測(cè)試");
    Console.WriteLine("beta測(cè)試");
    Console.WriteLine("uat測(cè)試");
    Console.WriteLine("系統(tǒng)上線");
}

運(yùn)行示例,結(jié)果如下所示:

通過(guò)運(yùn)行以上示例,發(fā)現(xiàn):順序確實(shí)符合預(yù)期,可以滿足要求,但是程序會(huì)卡住,這點(diǎn)不太友好。

如何才能優(yōu)雅的控制先后順序呢?Task還提供了TaskFactory,如下所示:

private void btnTask2_Click(object sender, EventArgs e)
{
    //開發(fā)前的工作
    Console.WriteLine("組建團(tuán)隊(duì)");
    Console.WriteLine("需求分析");
    Console.WriteLine("系統(tǒng)設(shè)計(jì)");
    Console.WriteLine("詳細(xì)設(shè)計(jì)");
    //開始開發(fā)
    List<Task> tasks = new List<Task>();
    tasks.Add(Task.Run(() => { Coding("張三", "接口"); }));
    tasks.Add(Task.Run(() => { Coding("李四", "前端頁(yè)面"); }));
    tasks.Add(Task.Run(() => { Coding("王五", "手機(jī)App"); }));
    tasks.Add(Task.Run(() => { Coding("劉大", "后端業(yè)務(wù)"); }));
    TaskFactory taskFactory = new TaskFactory();
    taskFactory.ContinueWhenAll(tasks.ToArray(), new Action<Task[]>((taskArray) => {
        //開發(fā)后的工作
        Console.WriteLine("alpha測(cè)試");
        Console.WriteLine("beta測(cè)試");
        Console.WriteLine("uat測(cè)試");
        Console.WriteLine("系統(tǒng)上線");
    }));

}

TaskFactory示例測(cè)試,如下所示:

通過(guò)對(duì)示例進(jìn)行分析,得出如下結(jié)論:

  1. 業(yè)務(wù)邏輯上已要求,頁(yè)面也不會(huì)卡頓,優(yōu)雅的實(shí)現(xiàn)了多線程的操作。
  2. Task產(chǎn)生的線程,為線程池線程。
  3. TaskFactory不僅提供了ContinueWhenAll等待所有線程,還提供了ContinueWhenAny等待任意線程。

以上就是C#多線程學(xué)習(xí)之Thread、ThreadPool、Task、Parallel四者區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于C# 多線程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 用C#編寫ActiveX控件(三)

    用C#編寫ActiveX控件(三)

    用C#編寫ActiveX控件(三)...
    2007-03-03
  • C#遞歸讀取XML菜單數(shù)據(jù)的方法

    C#遞歸讀取XML菜單數(shù)據(jù)的方法

    這篇文章主要介紹了C#遞歸讀取XML菜單數(shù)據(jù)的方法,涉及遞歸的操作技巧與C#窗體的用法,對(duì)于進(jìn)行C#項(xiàng)目開發(fā)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • 使用SkiaSharp在C#中如何生成圖像

    使用SkiaSharp在C#中如何生成圖像

    本文介紹了如何使用SkiaSharp庫(kù)在C#中生成和處理圖像,通過(guò)創(chuàng)建一個(gè)空白圖像并繪制一個(gè)正方形,我們展示了如何使用SkiaSharp的基本功能,如創(chuàng)建畫布、繪制圖形和保存圖像
    2025-01-01
  • WPF+SkiaSharp實(shí)現(xiàn)自繪投籃小游戲

    WPF+SkiaSharp實(shí)現(xiàn)自繪投籃小游戲

    這篇文章主要介紹了如何利用WPF+SkiaSharp實(shí)現(xiàn)自繪投籃小游戲。此案例主要是針對(duì)光線投影法碰撞檢測(cè)功能的示例,順便做成了一個(gè)小游戲,很簡(jiǎn)單,但是,效果卻很不錯(cuò),感興趣的可以動(dòng)手嘗試一下
    2022-08-08
  • 100行C#代碼實(shí)現(xiàn)經(jīng)典掃雷游戲

    100行C#代碼實(shí)現(xiàn)經(jīng)典掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了如何用100行C#代碼實(shí)現(xiàn)經(jīng)典的掃雷游戲,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2023-02-02
  • C#模式畫刷HatchBrush用法實(shí)例

    C#模式畫刷HatchBrush用法實(shí)例

    這篇文章主要介紹了C#模式畫刷HatchBrush用法,實(shí)例分析了模式畫刷HatchBrush繪圖的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • C#中DataGridView的樣式

    C#中DataGridView的樣式

    這篇文章主要介紹了C#中DataGridView的樣式設(shè)置方法,包括交替行顏色、單元格內(nèi)容有效性檢查、單元格的選擇模式等,需要的朋友可以參考下
    2015-02-02
  • Unity幸運(yùn)轉(zhuǎn)盤實(shí)戰(zhàn)項(xiàng)目

    Unity幸運(yùn)轉(zhuǎn)盤實(shí)戰(zhàn)項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了Unity幸運(yùn)轉(zhuǎn)盤實(shí)戰(zhàn)項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • c#執(zhí)行excel宏模版的方法

    c#執(zhí)行excel宏模版的方法

    這篇文章主要介紹了c#執(zhí)行excel宏模版的方法,導(dǎo)出Excel模版的代碼如下,大家參考使用吧
    2014-01-01
  • C#入門之索引器使用實(shí)例

    C#入門之索引器使用實(shí)例

    這篇文章主要介紹了C#的索引器使用方法,對(duì)此,C#初學(xué)者應(yīng)予以牢固掌握,需要的朋友可以參考下
    2014-08-08

最新評(píng)論

丹江口市| 安多县| 海南省| 安乡县| 五河县| 莱芜市| 阳西县| 肃南| 石城县| 普定县| 通化县| 罗源县| 庆城县| 石泉县| 芮城县| 南宫市| 霍山县| 鄂州市| 高要市| 苍梧县| 商城县| 洪湖市| 启东市| 区。| 灯塔市| 涞水县| 青海省| 团风县| 龙州县| 汕头市| 边坝县| 尤溪县| 崇信县| 奉新县| 五华县| 清原| 云梦县| 湄潭县| 托克托县| 大渡口区| 福海县|