C#多线程开发-任务并行库
你好,我是阿輝。
正文共2090字,預計閱讀時間:6min。
之前學習了線程池,知道了它有很多好處。
使用線程池可以使我們在減少并行度花銷時節省操作系統資源。可認為線程池是一個抽象層,其向程序員隱藏了使用線程的細節,使我們可以專心處理程序邏輯,而不是各種線程問題。
但也不是說我們所有的項目中都上線程池,其實它也有很多弊端,比如我們需要自定義使用異步委托的方式才可以將線程中的消息或異常傳遞出來。這些如果在一個大的軟件系統中,會導致軟件結構過于混亂,各個線程之間消息傳遞來傳遞去的,如果發生沒有處理掉的異常,很容易導致軟件出現致命錯誤。
為了解決這個問題,在.Net Framework 4.0中引入了一個新的異步操作的API,它叫任務并行庫(TPL)。
那么接下來,讓我們一起來認識一下這個TPL,看看它到底有什么魔力可以把線程池中的棘手問題解決掉。
任務并行庫
TPL又被認為是線程池的有一個抽象,其對程序員隱藏了線程池交互的底層代碼,并只提供了更方便的細粒度的API。
TPL的核心是任務。一個任務代表一個異步操作,該操作可以通過多種方式運行,可以使用或不使用獨立線程運行。
TPL有一個關鍵優勢,就是一個任務可以通過多種方式和其它任務組合起來。
比如可以同時開啟多個任務,等待所有任務完成,然后運行一個任務對之前所有任務的結果進行一些計算。
可以使用AggregateException來捕獲底層任務內部所有異常,并允許單獨處理這些異常。在C#5.0中已經內置了對TPL的支持,允許我們使用心得await和async關鍵字以平滑的、舒服的方式操作任務。
一、創建任務
可以通過下面三種方式來創建任務。
??????var?a1?=?new?Task(()=>TastMethod("線程01"));a1.Start();Task.Run(()=>TastMethod("線程001"));????//已棄用Task.Factory.StartNew(()=>TastMethod("線程02"));Task.Factory.StartNew(()?=>?TastMethod("線程03"),TaskCreationOptions.LongRunning);Console.ReadKey();在最新的.NET 5.0中已經將任務快速啟動方式Run,丟棄掉了。只能使用其余的兩種。實例化的Tast屬性,必須進行啟動,任務才可以執行。其余的.NET已經做了內置,只需要使用就默認自動開啟。
在線程3開啟過程中,增加了TaskCreationOptions.LongRuning參數,它表示標記該任務為長時間運行,結果該任務將不會使用線程池,而在單獨的線程中運行。然而根據運行該任務的當前任務調度程序,運行方式可能不同。
二、使用任務執行基本操作
下面介紹下從任務中得到其計算法返回的結果。
????????static?void?Main(string[]?args){???var?a1?=?new?Task<int>(()=>TastMethod("線程01"));a1.Start();int?result?=?a1.Result;????????????Console.WriteLine("result:"?+?result);Console.ReadKey();}static?int?TastMethod(string?name)?{Console.WriteLine("線程名字:"+name+"Id:"+Thread.CurrentThread.ManagedThreadId+"是否屬于線程池:"+Thread.CurrentThread.IsThreadPoolThread);return?40;} 輸出結果這里我們聲明并運行了線程01并等待結果,該任務會被放置在線程池中,并且主線程會等待,直到任務返回前一直處于阻塞狀態。
其實也可以調用方法RunSynchronously()方法,使其特定運行在主線程。這是一個非常好的優化,可以避免使用線程池來執行非常短暫的操作。
三、處理任務中的異常
在異步任務中,對于異常的處理是非常重要的。
????????????try{var?a1?=?new?Task<int>(()?=>?TastMethod("線程01",2));a1.Start();int?result?=?a1.Result;Console.WriteLine("result:"?+?result);}catch?(Exception?ex){Console.WriteLine(ex.Message);}??????當程序啟動時,創建了一個任務并嘗試同步獲取任務結果。Result屬性的Get部分會使當前線程等待直到該任務結束,并將異常傳播給當前線程。此時通過try/catch是很容易捕獲到的(需要注意AggregateExceptiont,它被封裝起來,)。
int?result?=?a1.GetAwaiter().GetResult?;上面這種情況無需封裝異常,可以使用GetAwaiter和GetResult方法來訪問任務結果。
小寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。
原創不易,給個關注。
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 ?謝謝。
C#多線程開發-線程基礎 01
C#多線程開發-線程同步02
C#多線程開發-線程池03
總結
以上是生活随笔為你收集整理的C#多线程开发-任务并行库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [019] C#基础:理解装箱与拆箱
- 下一篇: 【招聘(北京成都)】北森 招聘.NET