在异步方法中,等待(Await)和任务结果(Task.Result)有何区别?

117

以下两种方式有何不同:

async Task<T> method(){
    var r = await dynamodb.GetItemAsync(...)
    return r.Item;
}

对战

async Task<T> method(){
    var task = dynamodb.GetItemAsync(...)
    return task.Result.Item;
}

在我的情况下,出于某种原因,只有第二个有效。第一个似乎永远不会结束。


所以我发现await可能会挂起的唯一原因是来自下面的SO答案。我想在这里留下评论,以帮助未来的我。https://dev59.com/uWYr5IYBdhLWcg3wq7-Ihttps://dev59.com/S2kw5IYBdhLWcg3wbqES#10369275 - Cyrus Downey
1
尝试使用 await dynamodb.GetItemAsync(...).ConfigureAwait(false)。 - Jesper Mygind
2个回答

141

6
为什么在这种情况下 await 不起作用,但 Result 可以工作? - luis
15
缺乏其他信息,我认为唯一的答案是,在“await”情况下它实际上并没有起作用。你之所以认为它有效是因为该方法本身返回了。但是被等待的任务可能无论如何都不会完成。如果你想得到关于那个问题的答案(这是一个不同于你提出的问题),你需要发布一个新的问题,清楚地阐述并提供一个能够可靠地重现问题的好的、最小化的代码示例。 - Peter Duniho
4
调用 Result 是一个隐藏的死锁。 - Joshua
2
@user2953241:.Result 或其所有可能的变体会导致线程池线程等待线程池上的作业完成。这可能会耗尽线程池中的所有线程,使得没有线程执行实际工作。 - Joshua
在异步方法B中,如果调用者方法A立即等待方法B而不在调用B和等待B之间执行任何工作,使用await而不是.Result有什么意义? - Pedro Machado
显示剩余4条评论

34

task.Result 用于访问属性时的get访问器,会阻塞调用线程直到异步操作完成,它等效于调用Wait方法。 一旦操作结果可用,它将被存储并在后续调用Result属性时立即返回。请注意,如果任务操作期间发生异常或任务已被取消,则Result属性不会返回值。相反,试图访问属性值将抛出AggregateException异常。 唯一的区别在于await不会阻塞,而是异步等待Task完成,然后继续执行。


7
为什么在这种情况下await无法使用,但Result可以使用? - luis
5
Result称为裸类型是一种隐藏的死锁。 - Joshua
2
借鉴Joshua的想法,你可以在这里了解更多关于它为什么会导致隐藏死锁的信息:https://dev59.com/7WQm5IYBdhLWcg3w6CWr - Onosa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接