C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别
作者:无风听海
本文主要介绍了C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
一、概念对比
| 方法/属性 | 阻塞线程 | 调用 TaskAwaiter continuation | 异常处理 | 典型用途 |
|---|---|---|---|---|
| Task.Wait() | ✅ 阻塞调用线程 | ❌ 不触发 continuation | 抛 AggregateException | 同步等待 Task 完成,不关心结果 |
| Task.Result | ✅ 阻塞调用线程 | ❌ 不触发 continuation | 抛 AggregateException 包含 Task 异常 | 同步获取 Task 结果 |
| Task.GetAwaiter().GetResult() | ✅ 阻塞调用线程 | ❌ 不触发 continuation | 直接抛原始异常(不包 AggregateException) | 内部 await/框架调用同步获取 Task 结果,更精确异常 |
二、底层机制分析
1、 Task.Wait()
public void Wait() {
if (!IsCompleted)
WaitHelper.Wait(this, Timeout.Infinite, cancellationToken: default);
}
- 使用
WaitHelper.Wait(),内部通过ManualResetEventSlim或WaitHandle阻塞调用线程。 - 阻塞当前线程,等待 Task 完成(RunToCompletion/Faulted/Canceled)。
- 不触发 TaskAwaiter 的 continuation。
2、Task.Result
public T Result {
get {
Wait(); // 调用同步等待
return GetResult(); // 返回 Task<T> 结果
}
}
内部先阻塞等待 Task 完成(调用 Wait())。
然后返回 Task 结果或抛异常。
对异常处理不同:
Wait()或Result会把 Task 异常 封装为 AggregateException。
3、 Task.GetAwaiter().GetResult()
var awaiter = task.GetAwaiter(); awaiter.GetResult();
不阻塞 Task 的内部状态管理,直接使用 TaskAwaiter 的
GetResult():- 如果 Task 未完成 → 会阻塞调用线程等待完成
- 如果 Task 完成 → 直接返回结果或抛异常
与
Task.Result最大区别:- 异常不会包装成 AggregateException,而是抛原始异常
不触发 async continuation
三、线程行为对比
Caller Thread ├─ Task.Wait() / Task.Result / GetAwaiter().GetResult() | -> 阻塞当前线程 Task completes (ThreadPool/IOCP) ├─ Task signals wait handle Caller Thread unblocks ├─ Wait() 返回 / Result 返回 / GetResult() 返回或抛异常
注意:无论哪种方式,continuation 不会在阻塞线程上执行。
- async/await 的 continuation 依赖 OnCompleted / SynchronizationContext 调度
- 直接同步阻塞方法绕过了这些机制
四、异常处理差异
| 方法 | 异常类型 | 包装情况 |
|---|---|---|
| Task.Wait() | Task 异常 | AggregateException |
| Task.Result | Task 异常 | AggregateException |
| Task.GetAwaiter().GetResult() | Task 异常 | 原始异常(unwrap) |
⚠️ 这是为什么 GetAwaiter().GetResult() 更常在库内部使用,因为它可以避免额外的 AggregateException 包装,保持异常原样。
五、潜在风险
死锁
- 在 UI 线程调用
Wait()/Result,而 Task continuation 捕获 SynchronizationContext → continuation 无法执行 → 死锁。
- 在 UI 线程调用
线程阻塞
- 阻塞调用线程,浪费资源,ThreadPool 扩展可能触发饥饿。
六、总结
- Task.Wait() → 阻塞等待,无返回值,异常 AggregateException
- Task.Result → 阻塞等待,返回结果,异常 AggregateException
- Task.GetAwaiter().GetResult() → 阻塞等待,返回结果或抛原始异常,内部 await/框架常用
- 都不触发 continuation,阻塞线程可能导致死锁
- async/await 才是非阻塞、自动调度 continuation 的机制
到此这篇关于C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别的文章就介绍到这了,更多相关Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
