查看: 91|回复: 0

[教程] C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别

[复制链接]

2

主题

0

回帖

0

积分

积极分子

金币
0
阅读权限
220
精华
0
威望
0
贡献
0
在线时间
0 小时
注册时间
2010-9-8
发表于 2025-12-28 11:15:10 | 显示全部楼层 |阅读模式

一、概念对比

方法/属性阻塞线程调用 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(),内部通过 ManualResetEventSlimWaitHandle 阻塞调用线程。
  • 阻塞当前线程,等待 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.ResultTask 异常AggregateException
Task.GetAwaiter().GetResult()Task 异常原始异常(unwrap)

⚠️ 这是为什么 GetAwaiter().GetResult() 更常在库内部使用,因为它可以避免额外的 AggregateException 包装,保持异常原样。

五、潜在风险

  1. 死锁

    • 在 UI 线程调用 Wait() / Result,而 Task continuation 捕获 SynchronizationContext → continuation 无法执行 → 死锁。
  2. 线程阻塞

    • 阻塞调用线程,浪费资源,ThreadPool 扩展可能触发饥饿。

六、总结

  1. Task.Wait() → 阻塞等待,无返回值,异常 AggregateException
  2. Task.Result → 阻塞等待,返回结果,异常 AggregateException
  3. Task.GetAwaiter().GetResult() → 阻塞等待,返回结果或抛原始异常,内部 await/框架常用
  4. 都不触发 continuation,阻塞线程可能导致死锁
  5. async/await 才是非阻塞、自动调度 continuation 的机制

到此这篇关于C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别的文章就介绍到这了,更多相关Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!

您可能感兴趣的文章:
  • c# Task.Wait()与awaiat Task异常处理的区别说明
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部