我正在尝试理解async / await,看看我是否需要在我的ASP.NET MVC 5
应用程序中使用异步调用。
在使用值填充视图模型时,我有以下内容:
MyViewModel myViewModel = new MyViewModel();
myViewModel.Answer1 = await myService.CalculateAnswer1Async();
myViewModel.Answer2 = await myService.CalculateAnswer2Async();
以上两种方法背后的代码:
public async Task<int> CalculateAnswer1Async()
{
await Task.Delay(5000);
return 111;
}
public async Task<int> CalculateAnswer2Async()
{
await Task.Delay(6000);
return 222;
}
据我了解,上述两种方法将一个接一个地执行,先是CalculateAnswer1Async()
,然后是CalculateAnswer2Async()
。因此,完成此操作所需的最长时间应为6秒左右(CalculateAnswer2Async()完成所需的时间)?但是当我运行页面时,加载大约需要11秒,即5秒+6秒= 11秒。
有人可以帮我向我澄清一下我做错了吗?
答案 0 :(得分:4)
当您await
时,您将暂停当前的async
方法,直到该操作完成。释放线程以执行其他工作,但在await
完成之前,方法将不会继续执行。我的博客上有一个async
intro,可以更详细地描述这一点。
如果要同时执行多个异步请求,则可以延迟await
,直到所有任务都已启动。所以这是一个选择:
MyViewModel myViewModel = new MyViewModel();
var task1 = myService.CalculateAnswer1Async();
var task2 = myService.CalculateAnswer2Async();
myViewModel.Answer1 = await task1;
myViewModel.Answer2 = await task2;
使用Task.WhenAll
稍微提高效率(通常会产生更清晰/更清晰的代码):
MyViewModel myViewModel = new MyViewModel();
var task1 = myService.CalculateAnswer1Async();
var task2 = myService.CalculateAnswer2Async();
await Task.WhenAll(task1, task2);
myViewModel.Answer1 = await task1;
myViewModel.Answer2 = await task2;
如果所有操作都返回相同类型的值(在这种情况下为int
),那么您可以避免等待&#34;虚假等待&#34;使用Task.WhenAll
:
MyViewModel myViewModel = new MyViewModel();
var task1 = myService.CalculateAnswer1Async();
var task2 = myService.CalculateAnswer2Async();
var results = await Task.WhenAll(task1, task2);
myViewModel.Answer1 = results[0];
myViewModel.Answer2 = results[1];
答案 1 :(得分:1)
myViewModel.Answer1 = await myService.CalculateAnswer1Async();
这将阻止当前线程,直到myService.CalculateAnswer1Async()完成。 事实上,当你使用await关键字时,你告诉执行线程:“嘿等待unitl我完成了这个操作,然后你可以自由地推断下一行代码”。
编辑: 而myService.CalculateAnswer1Async();正在完成它的工作,主线程可以回到一些名为SynchronizationContext的东西,当myService.CalculateAnswer1Async()完成它的工作。它将返回并继续使用其他方法。
答案 2 :(得分:1)
在第一种方法完成后,您正在开始第二种方法CalculateAnswer2Async
,因为await
是第一种方法的结果。
立即等待异步操作的结果仅在UI线程中非常有用,因为它释放UI线程以执行其他工作而不是阻止它。但它不会引入并发性。
您要做的是启动第一个方法,然后启动第二个方法,然后在两个结果上调用await
。
var result1 = myService.CalculateAnswer1Async();
var result2 = myService.CalculateAnswer2Async();
myViewModel.Answer1 = await result1;
myViewModel.Answer2 = await result2;
async
/ await
不会自行引入并发性,并且所有代码都可以同步运行。但是使用async
和await
使您可以从异步调用中受益,同时仍然具有易于编写的代码,其行为大多与您对同步版本的预期相同。
答案 3 :(得分:1)
在这种情况下,等待阻止方法的执行,直到async方法完成为止,有效地逐个运行它们。
您实际想要做的是并行运行它们:
MyViewModel myViewModel = new MyViewModel();
Task<int>[] tasks = new []
{
myService.CalculateAnswer1Async();
myService.CalculateAnswer2Async();
};
Task.WaitAll(tasks);
myViewModel.Answer1 = tasks[0].Result;
myViewModel.Answer2 = tasks[1].Result;