C#中Task.Wait()、Task.Result、Task.GetAwaiter().GetResult()区别

 更新时间:2025年12月28日 11:15:10   作者:无风听海  
本文主要介绍了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(),内部通过 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# Winform 禁止用户调整ListView的列宽

    C# Winform 禁止用户调整ListView的列宽

    在使用 ListView 的时候, 有时我们不想让别人随意调整列宽, 或者某几列的列宽, 以便达到美观, 或者隐藏数据的作用. 那么可以用一下代码来实现
    2011-05-05
  • C#实现过滤html标签并保留a标签的方法

    C#实现过滤html标签并保留a标签的方法

    这篇文章主要介绍了C#实现过滤html标签并保留a标签的方法,文中的自定义函数采用正则过滤实现了该功能,是非常实用的技巧,需要的朋友可以参考下
    2014-09-09
  • 英雄联盟辅助lol挂机不被踢的方法(lol挂机脚本)

    英雄联盟辅助lol挂机不被踢的方法(lol挂机脚本)

    lol挂机不会被踢,调用API设置鼠标位置并模拟鼠标右键让人物走动
    2013-12-12
  • C#的并发机制优秀在哪你知道么

    C#的并发机制优秀在哪你知道么

    这篇文章主要为大家详细介绍了C#的并发机制,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • C# winform实现登陆次数限制

    C# winform实现登陆次数限制

    这篇文章主要介绍了C# winform实现登陆次数限制,相信大家都遇到过网站在用户多次输错密码之后会自动把账户冻结的情况,这种功能如何实现,下面小编为大家分享实现方法
    2016-05-05
  • C#用ComboBox控件实现省与市的联动效果的方法

    C#用ComboBox控件实现省与市的联动效果的方法

    这篇文章主要介绍了C#用ComboBox控件实现省与市的联动效果的方法,较为详细的分析了ComboBox控件的使用原理与相关技巧,需要的朋友可以参考下
    2015-01-01
  • 在WPF中使用Interaction.Triggers

    在WPF中使用Interaction.Triggers

    这篇文章介绍了在WPF中使用Interaction.Triggers的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • C# SQlite操作方法小结

    C# SQlite操作方法小结

    这篇文章主要介绍了C# SQlite操作方法,较为详细的讲述了SQLite的下载与C#针对SQLite的连接、创建、与执行SQL语句等操作相关技巧,需要的朋友可以参考下
    2016-07-07
  • 手动编译C#代码的方法

    手动编译C#代码的方法

    在本文里小编给大家分享的是关于手动编译C#代码的方法和步骤,对此有需要的朋友们可以学习下。
    2018-12-12
  • C#实现分治算法求解股票问题

    C#实现分治算法求解股票问题

    本文主要介绍了C#实现分治算法求解股票问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04

最新评论