C# 並行和多執行緒程式設計——認識和使用Task
對於多執行緒,我們經常使用的是Thread。在我們瞭解Task之前,如果我們要使用多核的功能可能就會自己來開執行緒,然而這種執行緒模型在.net 4.0之後被一種稱為基於“任務的程式設計模型”所衝擊,因為task會比thread具有更小的效能開銷,不過大家肯定會有疑惑,任務和執行緒到底有什麼區別呢?
任務和執行緒的區別:
1、任務是架構線上程之上的,也就是說任務最終還是要拋給執行緒去執行。
2、任務跟執行緒不是一對一的關係,比如開10個任務並不是說會開10個執行緒,這一點任務有點類似執行緒池,但是任務相比執行緒池有很小的開銷和精確的控制。
一、認識Task和Task的基本使用
1、認識Task
首先來看一下Task的繼承結構。Task標識一個非同步操作。
可以看到Task和Thread一樣,位於System.Threading名稱空間下,這也就是說他們直接有密不可分的聯絡。下面我們來仔細看一下吧!
2、建立Task
建立Task的方法有兩種,一種是直接建立——new一個出來,一種是通過工廠建立。下面來看一下這兩種建立方法:
1 2 3 4 5 |
|
這是最簡單的建立方法,可以看到其建構函式是一個Action,其建構函式有如下幾種,比較常用的是前兩種。
1 2 3 4 5 |
|
這種方式通過靜態工廠,建立以個Task並執行。下面我們來建一個控制檯專案,演示一下,程式碼如下:
要新增System.Threading.Tasks命名控制元件引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
這裡我分別用兩種方式建立兩個task,並讓他們執行。可以看到通過建構函式建立的task,必須手動Start,而通過工廠建立的Task直接就啟動了。
下面我們來看一下Task的宣告週期,編寫如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
task1.Status就是輸出task的當前狀態,其輸出結果如下:
可以看到呼叫Start前的狀態是Created,然後等待分配執行緒去執行,到最後執行完成。
從我們可以得出Task的簡略生命週期:
Created:表示預設初始化任務,但是“工廠建立的”例項直接跳過。
WaitingToRun: 這種狀態表示等待任務排程器分配執行緒給任務執行。
RanToCompletion:任務執行完畢。
二、Task的任務控制
Task最吸引人的地方就是他的任務控制了,你可以很好的控制task的執行順序,讓多個task有序的工作。下面來詳細說一下:
1、Task.Wait
在上個例子中,我們已經使用過了,task1.Wait();就是等待任務執行完成,我們可以看到最後task1的狀態變為Completed。
2、Task.WaitAll
看字面意思就知道,就是等待所有的任務都執行完成,下面我們來寫一段程式碼演示一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
其輸出結果如下:
可以看到,任務一和任務二都完成以後,才輸出All task finished!
3、Task.WaitAny
這個用發同Task.WaitAll,就是等待任何一個任務完成就繼續向下執行,將上面的程式碼WaitAll替換為WaitAny,輸出結果如下:
4、Task.ContinueWith
就是在第一個Task完成後自動啟動下一個Task,實現Task的延續,下面我們來看下他的用法,編寫如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
執行結果如下:
可以看到,task1完成之後,開始執行後面的內容,並且這裡我們取得task的返回值。
在每次呼叫ContinueWith方法時,每次會把上次Task的引用傳入進來,以便檢測上次Task的狀態,比如我們可以使用上次Task的Result屬性來獲取返回值。我們還可以這麼寫:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
首先輸出Get some data,然後執行第二個獲得返回值true,最後根據判斷返回Finished或error。輸出結果:
Get some Data! Finished
其實上面的寫法簡化一下,可以這樣寫:
1 |
|
輸出One,這個可以看明白了吧~
更多ContinueWith用法參見:http://technet.microsoft.com/zh-CN/library/dd321405
5、Task的取消
前面說了那麼多Task的用法,下面來說下Task的取消,比如我們啟動了一個task,出現異常或者使用者點選取消等等,我們可以取消這個任務。
如何取消一個Task呢,我們通過cancellation的tokens來取消一個Task。在很多Task的Body裡面包含迴圈,我們可以在輪詢的時候判斷IsCancellationRequested屬性是否為True,如果是True的話就return或者丟擲異常,丟擲異常後面再說,因為還沒有說異常處理的東西。
下面在程式碼中看下如何實現任務的取消,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
這裡開啟了一個Task,並給token註冊了一個方法,輸出一條資訊,然後執行ReadKey開始等待使用者輸入,使用者點選回車後,執行tokenSource.Cancel方法,取消任務。其輸出結果如下:
往期 精彩 回顧
.NET Core實戰專案之CMS 第一章 入門篇-開篇及總體規劃
【.NET Core微服務實戰-統一身份認證】開篇及目錄索引
Redis基本使用及百億資料量中的使用技巧分享(附影片地址及觀看指南)
.NET Core中的一個介面多種實現的依賴注入與動態選擇看這篇就夠了
用abp vNext快速開發Quartz.NET定時任務管理介面
- ASP.NET Core在.NET 7 RC1中的更新
- 如何設計一個支援百萬使用者的系統
- 分享一個基於.NET6包含DDD,ES,CQRS等概念的開源專案
- [第二篇]如何在ASP.Net Core的生產環境中使用OAuth保護swagger ui
- 如何在C#中使用Channels進行非同步排隊
- 話說C#程式設計師人手一個ORM
- 快速理解ASP.NET Core的認證與授權
- 如何在 C# 中使用 插值字串?
- C#10在List, Queue 以及Stack中使用EnsureCapacity方法來提升效能
- 如何主動清空.NET資料庫連線池?
- 基於 gRPC 和 .NET Core 的伺服器流
- 三分鐘總覽微軟任務並行庫TPL
- .NET 6 Preview5 VS2022實戰千萬併發秒殺專案,帥爆了(附原始碼)
- c#如何建立使用者自定義異常?
- 讓Dapper在一個專案中支援多種庫
- 深入LINQ | 動態構建LINQ表示式
- C# 並行和多執行緒程式設計——認識和使用Task
- C# 動態編譯簡介
- C#中HashTable、Dictionary、ConcurrentDictionary區別
- 微軟強推!64位Visual Studio 2022帶來這些新變化!