关于 await 和task.result的区别的疑惑

文章讨论了在C#中使用await关键字与Task.Result属性的区别。await允许异步等待,不阻塞当前线程,而Task.Result会导致线程阻塞,可能引发线程死锁。尽管.result在某些情况下可工作,但按照微软的最佳实践,async/await是推荐的,特别是在服务端处理高并发时,能更有效地管理线程并提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题背景介绍:

今天在给一个方法加业务时,需要提前使用一个本来应该返回给调用者使用的实体。就造出了如下图所示的代码形式,  专门创建一个对象接收await task得到的实体。使用完毕之后,还要被IDE强制要求 await task一次。

然后我觉得这样await一个task两次,有点脱裤子放屁的感觉,又改造出如下的效果,用task.result的方式来阻塞获取id。 

二、问题解惑

然后我网上查了一下这两个写法的区别,更迷糊了。网上对await 和task.result的区别解释有下面内容:

解释一:

一般来说,是的.await task;将"屈服"当前线程.task.Result将阻止当前线程.await是异步等待; Result是一个阻塞等待.

还有一个更小的区别:如果任务在故障状态下完成(即有异常),那么await将(重新)按原样引发异常,但Result会将异常包装在一个AggregateException.

 解释二:

await或者 .result/ .getwaiter().getresult() 这两个的区别在于,当遇到await会把线程挂起,开启别的线程继续后面的操作。但是遇到 .result会一直等在这里,不会开新的线程。很容易造成线程阻塞。 如果有两处使用 .result 还会导致互相等待 造成线程死锁
 

三、总结:

总体来看,好像用await比用.result更合适一点。

我在群内提问,有位大佬说的原话如下,我觉得非常有道理。

.result这种写法,不是不行,是不规范,微软官方倡导async到底,async await在服务端的作用不是十分明显,要看到明显的作用是在桌面端ui刷新的时候使用async 不会阻塞ui线程,服务端的话,是在一定并发量下才会发挥作用,async await还会涉及到请求线程和io线程,io线程经常是耗时的,没有async await之前,请求线程要等待io读写完成之后响应请求,然后这个请求线程才能空闲下来处理其他进来的请求,但是现在它不需要等待了,它把上下文交给了io线程来处理,甚至帮它把接下来的响应请求也处理了,它一定程度上节省了io等待的时间,快速回到请求线程池的队列中,随时准备处理接下来的请求。

### C# 中 `Task.Wait` `await Task.Run` 的区别及用法 #### 使用场景差异 当处理异步编程时,`Task.Wait` 是一种阻塞调用方法,它会等待指定的任务完成执行。而 `await Task.Run` 则是非阻塞的方式,在不阻碍当前线程的情况下继续其他操作直到任务完成。 对于如下同步方法: ```csharp double ComputeNumber() { // Simulate work Thread.Sleep(5000); // Return some number return 1.0; } ``` 将其转换成异步形式可以采用 `async Task<double>` 来返回结果[^1]。此时如果要比较两种方式,则有下面的例子来说明两者的不同之处。 #### 实现对比 ##### 使用 `Task.Wait` ```csharp public void UsingTaskWait() { var task = Task.Run(() => ComputeNumber()); task.Wait(); // 阻塞主线程直至计算结束 Console.WriteLine($"Computed Number: {task.Result}"); } ``` 这段代码会在遇到 `.Wait()` 方法时暂停整个程序流程,直到后台运行的任务完成后才会继续向前推进逻辑。这种方式虽然简单直接但是并不推荐用于UI或其他需要保持响应性的环境中因为这会导致界面冻结等问题。 ##### 使用 `await Task.Run` ```csharp public async Task UsingAwaitTaskRun() { double result = await Task.Run(() => ComputeNumber()); // 不会阻塞主线程 Console.WriteLine($"Computed Number: {result}"); } ``` 相比之下,这里通过 `await` 关键字实现了更加优雅的解决方案——允许应用程序在等待长时间运算的同时还能做别的事情而不必担心卡顿现象的发生。这种方法非常适合于现代多核处理器架构下的并发处理需求。 #### 性能考量 使用 `Task.Wait` 可能在某些情况下引发死锁问题特别是当你在一个已经标记为 `[STAThread]` 或者具有特定Synchronization Context环境里尝试去阻止一个异步过程的时候;相反地,利用 `await` 结合 `Task.Run` 能够有效规避此类风险并提高整体性能表现。 综上所述,在大多数实际应用场景下建议优先选用基于 `await` 的方案来进行异步开发实践以获得更好的用户体验以及更高的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值