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()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Unity Shader片段着色器使用基础详解

    Unity Shader片段着色器使用基础详解

    顶点-片段着色器是Unity Shader中最基础的着色器类型,用于控制3D模型的渲染效果。通过顶点着色器计算模型的顶点位置和法线方向,再通过片段着色器计算模型表面的颜色、光照、阴影等效果
    2023-05-05
  • C#实现Excel动态生成PivotTable

    C#实现Excel动态生成PivotTable

    这篇文章主要为大家详细介绍了C#实现Excel动态生成PivotTable的相关方法,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • C#中Lambda表达式的用法

    C#中Lambda表达式的用法

    这篇文章介绍了C#中Lambda表达式的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C# winform分页查询的实现示例

    C# winform分页查询的实现示例

    这篇文章主要介绍了C# winform分页查询的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 如何用C#获取计算机详细的软件和硬件信息

    如何用C#获取计算机详细的软件和硬件信息

    我们应该都知道System.Management提供的类可以用于读取本地计算机设备的各种数据,下面这篇文章主要给大家介绍了关于如何用C#获取计算机详细的软件和硬件信息的相关资料,需要的朋友可以参考下
    2022-12-12
  • C#实现动态数据绘图graphic的方法示例

    C#实现动态数据绘图graphic的方法示例

    这篇文章主要介绍了C#实现动态数据绘图graphic的方法,结合实例形式分析了C#根据动态数据绘制2D数据表格的相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • C#窗体全屏功能实例代码

    C#窗体全屏功能实例代码

    简要介绍窗体全屏的方法,列出实现窗体的全屏功能以及全屏功能的快捷键的代码,需要的朋友可以参考下
    2016-11-11
  • C# 实现微信自定义分享的示例代码

    C# 实现微信自定义分享的示例代码

    这篇文章主要介绍了C# 实现微信自定义分享的示例代码,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,感兴趣的同学可以自己动手尝试一下
    2024-02-02
  • 配置C#的系统环境变量的方法

    配置C#的系统环境变量的方法

    配置C#的系统环境变量的方法...
    2007-03-03
  • C#之继承实现

    C#之继承实现

    本文详细讲解了C#之继承的实现,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04

最新评论