真正帮助我理解 async-await 的是 Eric Lippert 在this interview 中描述的厨师类比。在中间某处搜索 async-await。
在这里,他描述了一位正在做早餐的厨师。一旦他把水壶烧开来泡茶,他就不会闲着等水煮好了。相反,他把面包放在烤面包机里,茶放在茶壶里,然后开始切西红柿:每当他必须等待另一台机器或其他厨师完成他的工作时,他不会无所事事,而是开始下一个任务,直到他需要之前任务之一的结果。
异步等待也是如此:每当另一个进程必须做某事时,您的线程除了等待另一个进程完成之外什么都不做,该线程可以环顾四周,看看它是否可以做其他事情。当涉及另一个冗长的过程时,您通常会看到 async-await:将数据写入文件、从数据库或 Internet 查询数据。每当您的线程必须执行此操作时,该线程可以命令其他进程执行某些操作,同时继续执行其他操作:
Task<string> taskReadFile = ReadMyFileAsync(...);
// not awaiting, we can do other things:
DoSomethingElse();
// now we need the result of the file:
string fetchedData = await taskReadFile;
那么会发生什么。 ReadMyFileAsync 是异步的,因此您知道在其内部某处,该方法正在等待。事实上,如果您忘记等待,编译器会发出警告。
一旦你的线程看到等待,它就知道需要等待的结果,所以它不能继续。相反,它会向上调用堆栈继续处理(在我的示例中为 DoSomethingElse()),直到它看到等待。它再次向上调用堆栈并继续处理,等等。
因此,实际上您的第一种方法和第二种方法之间没有真正的区别。您可以将其与以下内容进行比较:
double x = Math.Sin(4.0)
对
double a = 4.0;
double x = Math.Sin(a);
官方唯一的区别是在这些语句之后你仍然可以使用 a.同样,您可以在等待之后使用来自任务的信息:
Task<MyData> myTask = FetchMyDataAsync(...);
MyData result = await myTask;
// if desired you can investigate myTask
if (result == null)
{
// why is it null, did someone cancel my task?
if (Task.IsCanceled)
{
Yell("Hey, who did cancel my task!");
}
}
但大多数时候你对任务不感兴趣。如果您在执行任务时没有其他事情可做,我会等待它:
MyData fetchedData = await FetchMyDataAsync(...)