我在书中读到了下面的差异。
private async Task GetDataAsync() {
var task1 = ReadDataFromIOAsync();
var task2 = ReadDataFromIOAsync();
// Here we can do more processing
// that doesn't need the data from the previous calls.
// Now we need the data so we have to wait
await Task.WhenAll(task1, task2);
// Now we have data to show.
lblResult.Content = task1.Result;
lblResult2.Content = task2.Result;
}
private async Task GetDataAsync() {
var task1 = ReadDataFromIOAsync();
var task2 = ReadDataFromIOAsync();
lblResult.Content = await task1;
lblResult2.Content = await task2;
}
我理解第一种方法的await语句中发生了什么。但对于第二个,虽然我理解逻辑我无法理解第二个实现与第一个实现相比的缺陷。在书中,他们提到编译器会重写该方法两次。我理解的是因为两个等待呼叫,可能会有比第一个更多的时间延迟,因为我们在这里单独调用等待每个任务。有人可以用更好的方式解释我吗?
答案 0 :(得分:1)
我不知道你的书想要做什么,但我同意你对它的互操作的初步猜测。
问题可能是lblResult
显示新数据可能会有一段时间,如果lblResult2
需要的时间超过task2
,则task1
会显示旧数据。在第一种方法中,您等待两个任务完成,然后同时更新两个标签(当您退出方法时,两者同时在屏幕上重新绘制)。在第二种方法中,您更新第一个标签,然后为消息循环提供重新绘制屏幕的机会,然后一段时间后更新第二个标签并在屏幕上更新该值。
我猜你的第二个例子也会有一个稍微更复杂的状态机,但是开销可以忽略不计,我相信这本书试图指出你和我这两个问题想出来了。
答案 1 :(得分:1)
基本上第一种方法是做什么的:
task1
task2
task1
和 task2
完成第二个实现是这样做的:
task1
task2
task1
完成。task1
完成后,继续执行,然后异步等待task2
完成。因此,使用第二种方法,您将单独等待每项任务的结果,而不是等待两项任务完成。在task1
在task2
之前完成的情况下,代码将继续执行然后立即返回,这将导致额外的上下文切换,这可能需要额外的时间。此外,对于多个等待的情况,编译器可能最终生成更复杂的状态机,但其影响应该可以忽略不计。
在任何一种情况下,在两个任务完成之前你都没有使用结果,所以应用程序的行为不应该太不相同。