C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()區(qū)別
一、概念對(duì)比
| 方法/屬性 | 阻塞線程 | 調(diào)用 TaskAwaiter continuation | 異常處理 | 典型用途 |
|---|---|---|---|---|
| Task.Wait() | ? 阻塞調(diào)用線程 | ? 不觸發(fā) continuation | 拋 AggregateException | 同步等待 Task 完成,不關(guān)心結(jié)果 |
| Task.Result | ? 阻塞調(diào)用線程 | ? 不觸發(fā) continuation | 拋 AggregateException 包含 Task 異常 | 同步獲取 Task 結(jié)果 |
| Task.GetAwaiter().GetResult() | ? 阻塞調(diào)用線程 | ? 不觸發(fā) continuation | 直接拋原始異常(不包 AggregateException) | 內(nèi)部 await/框架調(diào)用同步獲取 Task 結(jié)果,更精確異常 |
二、底層機(jī)制分析
1、 Task.Wait()
public void Wait() {
if (!IsCompleted)
WaitHelper.Wait(this, Timeout.Infinite, cancellationToken: default);
}
- 使用
WaitHelper.Wait(),內(nèi)部通過(guò)ManualResetEventSlim或WaitHandle阻塞調(diào)用線程。 - 阻塞當(dāng)前線程,等待 Task 完成(RunToCompletion/Faulted/Canceled)。
- 不觸發(fā) TaskAwaiter 的 continuation。
2、Task.Result
public T Result {
get {
Wait(); // 調(diào)用同步等待
return GetResult(); // 返回 Task<T> 結(jié)果
}
}
內(nèi)部先阻塞等待 Task 完成(調(diào)用 Wait())。
然后返回 Task 結(jié)果或拋異常。
對(duì)異常處理不同:
Wait()或Result會(huì)把 Task 異常 封裝為 AggregateException。
3、 Task.GetAwaiter().GetResult()
var awaiter = task.GetAwaiter(); awaiter.GetResult();
不阻塞 Task 的內(nèi)部狀態(tài)管理,直接使用 TaskAwaiter 的
GetResult():- 如果 Task 未完成 → 會(huì)阻塞調(diào)用線程等待完成
- 如果 Task 完成 → 直接返回結(jié)果或拋異常
與
Task.Result最大區(qū)別:- 異常不會(huì)包裝成 AggregateException,而是拋原始異常
不觸發(fā) async continuation
三、線程行為對(duì)比
Caller Thread ├─ Task.Wait() / Task.Result / GetAwaiter().GetResult() | -> 阻塞當(dāng)前線程 Task completes (ThreadPool/IOCP) ├─ Task signals wait handle Caller Thread unblocks ├─ Wait() 返回 / Result 返回 / GetResult() 返回或拋異常
注意:無(wú)論哪種方式,continuation 不會(huì)在阻塞線程上執(zhí)行。
- async/await 的 continuation 依賴 OnCompleted / SynchronizationContext 調(diào)度
- 直接同步阻塞方法繞過(guò)了這些機(jī)制
四、異常處理差異
| 方法 | 異常類(lèi)型 | 包裝情況 |
|---|---|---|
| Task.Wait() | Task 異常 | AggregateException |
| Task.Result | Task 異常 | AggregateException |
| Task.GetAwaiter().GetResult() | Task 異常 | 原始異常(unwrap) |
?? 這是為什么 GetAwaiter().GetResult() 更常在庫(kù)內(nèi)部使用,因?yàn)樗梢员苊忸~外的 AggregateException 包裝,保持異常原樣。
五、潛在風(fēng)險(xiǎn)
死鎖
- 在 UI 線程調(diào)用
Wait()/Result,而 Task continuation 捕獲 SynchronizationContext → continuation 無(wú)法執(zhí)行 → 死鎖。
- 在 UI 線程調(diào)用
線程阻塞
- 阻塞調(diào)用線程,浪費(fèi)資源,ThreadPool 擴(kuò)展可能觸發(fā)饑餓。
六、總結(jié)
- Task.Wait() → 阻塞等待,無(wú)返回值,異常 AggregateException
- Task.Result → 阻塞等待,返回結(jié)果,異常 AggregateException
- Task.GetAwaiter().GetResult() → 阻塞等待,返回結(jié)果或拋原始異常,內(nèi)部 await/框架常用
- 都不觸發(fā) continuation,阻塞線程可能導(dǎo)致死鎖
- async/await 才是非阻塞、自動(dòng)調(diào)度 continuation 的機(jī)制
到此這篇關(guān)于C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()區(qū)別的文章就介紹到這了,更多相關(guān)Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)Excel動(dòng)態(tài)生成PivotTable
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Excel動(dòng)態(tài)生成PivotTable的相關(guān)方法,感興趣的小伙伴們可以參考一下2016-04-04
C# winform分頁(yè)查詢的實(shí)現(xiàn)示例
這篇文章主要介紹了C# winform分頁(yè)查詢的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
如何用C#獲取計(jì)算機(jī)詳細(xì)的軟件和硬件信息
我們應(yīng)該都知道System.Management提供的類(lèi)可以用于讀取本地計(jì)算機(jī)設(shè)備的各種數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于如何用C#獲取計(jì)算機(jī)詳細(xì)的軟件和硬件信息的相關(guān)資料,需要的朋友可以參考下2022-12-12
C#實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)繪圖graphic的方法示例
這篇文章主要介紹了C#實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)繪圖graphic的方法,結(jié)合實(shí)例形式分析了C#根據(jù)動(dòng)態(tài)數(shù)據(jù)繪制2D數(shù)據(jù)表格的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09

