您写道:“...因为 asyncTask1 和 asyncTask2 都是并行执行的。”
不,他们不是!
补充:下面我写了 async-await 中的一切都是由一个线程执行的。 Schneider 正确地评论说,在 async-await 中可以涉及多个线程。见最后的补充。
this interview with Eric-Lippert 将 async/await 与做饭的厨师进行了比较,这对我了解 async-await 的工作原理有很大帮助。 (中途某处,搜索 async-await)。
Eric Lippert 解释说,如果厨师开始做某事并在一段时间后发现他无事可做,只能等待一个过程完成,那么这位厨师会环顾四周,看看他是否可以做其他事情而不是等待。
使用 async/await 时,仍然涉及一个线程。这个线程一次只能做一件事。当线程忙于执行Task1 时,它无法执行Task2。只有在 Task1 中找到 await 时,才会开始执行 Task2 中的语句。在您的场景 2 中,任务不是并行执行的。
但是,场景之间存在差异。在场景 1 中,task2 的第一条语句在 task1 完全完成之前不会执行。场景 2 将在 task1 遇到 await 时立即开始执行 task2 的第一条语句。
如果您真的希望 task2 在 task1 也在做某事的同时做某事,那么您必须在单独的线程中开始执行 task2。在您的场景中执行此操作的简单方法是:
var task1 = Task.Run( () => asyncTask1())
// this statement is executed while task1 begins executing on a different thread.
// hence this thread is free to do other things, like performing statements
// from task2:
var task2 = asyncTask();
// the following statement will only be executed if task2 encounters an await
DoSomethingElse();
// when we need results from both task1 and task2:
await Task.WhenAll(new Task[] {task1, task2});
所以通常情况下,如果您需要该任务的结果,最好只等待任务完成。只要你能做其他事情,做这些其他事情,它们会在其他任务开始等待时立即执行,直到你开始等待,在这种情况下,你的调用者将开始做事情,直到他的等待等。
上述并行处理方法的优点是多方面的:
- 一切都由一个线程执行:不需要互斥锁,没有死锁、饥饿等的机会
- 您的代码看起来很有顺序。将此与使用 Task.ContinueWith 和类似语句的代码进行比较
- 启动单独的线程/从线程池运行线程没有开销
补充:下面施耐德关于几个线程的评论是正确的。
一些测试表明,等待任务中当前线程的线程 ID 与调用线程的线程 ID 不同。
对于异步等待的新手来说,重要的是要了解虽然涉及到各种线程,但异步等待并不意味着任务是并行执行的。如果您想要并行性,您必须特别说明该任务必须并行运行。
似乎 Eric Lippert 类比中的厨师实际上是一个厨师团队,他们不断地环顾四周,看看他们是否可以帮助其他一些厨师,而不是等待他们的任务完成。事实上,如果厨师 Albert 看到等待并开始做其他事情,厨师 Bernard 可能会完成厨师 Albert 的任务。