人们常常认为 async-await 是由多个线程完成的。事实上这一切都是由一个线程完成的。
请参阅下面关于这一线程语句的补充
对我理解 async-await 有很大帮助的是Eric Lippert 的关于 async-await 的采访 http://www.i-programmer.info/professional-programmer/i-programmer/7154-c-guru-an-interview-with-eric-lippert.html?start=1。在中间的某个地方,他将异步等待与必须等待水烧开的厨师进行了比较。他没有什么都不做,而是环顾四周,看看是否还有其他事情要做,比如切洋葱。如果完成后,水仍然没有沸腾,他会检查是否还有其他事情要做,依此类推,直到他除了等待之外无事可做。在这种情况下,他会回到他等待的第一件事。
如果您的过程调用可等待函数,我们确信在此可等待函数中的某个位置调用了可等待函数,否则该函数将不会可等待。事实上,如果您忘记在可等待函数中的某个位置等待,编译器会警告您。
如果您的可等待函数调用另一个可等待函数,则线程进入另一个函数并开始执行该函数中的操作,并深入到其他函数,直到遇到等待。
该线程没有等待结果,而是在其调用堆栈中向上查看是否还有其他可以处理的代码片段,直到看到等待。再次进入调用堆栈,处理直到等待,等等。一旦每个人都在等待,线程就会寻找底部的等待,并在完成后继续。
这样做的优点是,如果可等待函数的调用者不需要函数的结果,但可以在需要结果之前执行其他操作,则这些其他操作可以由线程完成,而不是在函数内等待。
不立即等待结果的调用将如下所示:
private async Task MyFunction()
{
Task<ReturnType>taskA = SomeFunctionAsync(...)
// I don't need the result yet, I can do something else
DoSomethingElse();
// now I need the result of SomeFunctionAsync, await for it:
ReturnType result = await TaskA;
// now you can use object result
}
请注意,在这种情况下,一切都由一个线程完成。只要你的线程有事可做,他就会很忙。
添加。只涉及一个线程是不正确的。任何无事可做的线程都可能在等待后继续处理您的代码。如果你检查线程id,你会发现这个id在await之后是可以改变的。持续的线程具有相同的context
作为原始线程,因此您可以像原始线程一样操作。无需检查InvokeRequired
,无需使用互斥体或临界区。对于您的代码来说,这就好像涉及一个线程。
本答案末尾的文章链接解释了有关线程上下文的更多信息
您将看到可等待函数,主要是在其他进程必须执行某些操作的情况下,而您的线程只需空闲等待直到其他操作完成。例如通过互联网发送数据、保存文件、与数据库通信等。
然而,有时必须完成一些繁重的计算,并且您希望线程可以自由地执行其他操作,例如响应用户输入。在这种情况下,您可以像调用异步函数一样启动可等待操作。
Task<ResultType> LetSomeoneDoHeavyCalculations(...)
{
DoSomePreparations()
// start a different thread that does the heavy calculations:
var myTask = Task.Run( () => DoHeavyCalculations(...))
// now you are free to do other things
DoSomethingElse();
// once you need the result of the HeavyCalculations await for it
var myResult = await myTask;
// use myResult
...
}
现在,另一个线程正在执行繁重的计算,而您的线程可以自由地执行其他操作。一旦开始等待,您的呼叫者就可以做一些事情,直到他开始等待。实际上,您的线程将相当自由地对用户输入做出反应。然而,这只有在所有人都在等待的情况下才会发生。当您的线程忙于执行操作时,您的线程无法对用户输入做出反应。因此,如果您认为 UI 线程必须执行一些需要一些时间的繁忙处理,请始终确保使用 Task.Run 并让另一个线程执行此操作
另一篇对我有帮助的文章:Async-Await 由出色的解释者 Stephen Cleary 撰写 http://blog.stephencleary.com/2012/02/async-and-await.html