await Task<T> 和 Task<T>.Result 有啥区别?
Posted
技术标签:
【中文标题】await Task<T> 和 Task<T>.Result 有啥区别?【英文标题】:What is the difference between await Task<T> and Task<T>.Result?await Task<T> 和 Task<T>.Result 有什么区别? 【发布时间】:2015-02-12 09:11:12 【问题描述】:public async Task<string> GetName(int id)
Task<string> nameTask = Task.Factory.StartNew(() => string.Format("Name matching id 0 = Developer", id));
return nameTask.Result;
在上面的方法返回语句中,我使用了Task<T>.Result
属性。
public async Task<string> GetName(int id)
Task<string> nameTask = Task.Factory.StartNew(() => string.Format("Name matching id 0 = Developer", id));
return await nameTask;
我在这里使用await Task<T>
。如果我认为 await 会释放调用线程但Task<T>.Result
会阻塞它,我不会错,对吗?
【问题讨论】:
由于第二个代码没有延续 - 你什么也得不到。在第一个代码中,您只需将方法标记为异步,但您不等待。 要了解有关async-await
的更多信息,请查看my async-await
curation 上的文章。
@RoyiNamir,你的说法不正确吗?第一种方法通过使用async
没有任何收获,因为该方法阻塞了调用线程。但是,第二种方法应该让出当前线程并且在任务设置为完成状态之前不会阻塞。
@MattWolf - 我同意第二种方法对调用它的任何方法都有好处,通过在任务完成时让它将控制权交还给调用者。
【参考方案1】:
如果我认为 await 会释放调用线程但 Task.Result 会阻塞它,我不会错,对吗?
你是对的,只要任务没有同步完成。如果是这样,使用Task.Result
或await task
将同步执行,因为await
将首先检查任务是否已完成。否则,如果任务没有完成,它将阻塞Task.Result
的调用线程,而使用await
将a同步等待任务完成。另一个不同的是异常处理。前者将传播AggregationException
(可能包含一个或多个异常),而后者将解包并返回底层异常。
附带说明,using asynchronous wrappers over sync methods is bad practice and should be avoided. 此外,在异步方法中使用 Task.Result
会导致死锁,也应避免。
【讨论】:
这种“在异步方法中使用Task.Result会导致死锁”怎么会发生死锁,你能详细说明一下吗?【参考方案2】:如果我认为 await 会释放调用线程但 Task.Result 会阻塞它,我不会错,对吗?
一般来说,是的。 await task;
将“让出”当前线程。 task.Result
将阻塞当前线程。 await
是异步等待; Result
是阻塞等待。
还有另一个更小的区别:如果任务在错误状态下完成(即,出现异常),则await
将(重新)按原样引发该异常,但Result
会将异常包装在一个AggregateException
。
附带说明,请避免使用Task.Factory.StartNew
。它几乎从来都不是正确的使用方法。如果您需要在后台线程上执行工作,请首选Task.Run
。
Result
和 StartNew
都适用,如果你正在做 dynamic task parallelism;否则,应避免使用它们。如果您正在使用asynchronous programming,则两者都不合适。
【讨论】:
感谢 Stephen Cleary 和 Yuval Itzchakov 提供更多相关知识。 在await Task.WhenAll(task1, task2)
之后得到结果有什么不同吗? await task1
与 task1.Result
?等待WhenAll
应该已经用线程完成了所有工作,对吧?
@demo:我更喜欢 await
有两个原因:1)它避免了 AggregateException
包装器,以及 2)它对代码更改更加宽容 - 即,如果有人更早地更改方法,现在任务不再完成。以上是关于await Task<T> 和 Task<T>.Result 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 IAsyncEnumerable 比返回 async/await Task<T> 慢?
深入了解异步async/await,为啥这种异步的性能这么高?异步的原理,本文彻底来个说明