在已经拆分的上下文上调用 await 时是否有开销?

Is there overhead when calling await on already split context?

编辑:我的问题并没有真正意义,因为我误解了任务的工作方式。我已将 stephen cleary 的回答标记为已接受,因为它为我指明了学习错误的方向。

我经常看到这样的代码:

public async Task DoSomething(){
     await DoSomethingElse();
     await DoSoManyThings();
     await DoEverything();
}

现在我看到的是第一个 await 启动第二个线程,returns 控制调用线程。当 await 完成时,将调用第二个 await。现在这是我可能会感到困惑的地方。第二个 await 拆分上下文/创建新线程,另一个线程消失(returns 给调用者)。这有开销吗?如果是这样,多少钱?最好让我的代码如下,以避免无缘无故地创建新线程:

public async Task DoSomething(){
     await DoSomethingElse();
      DoSoManyThings();
      DoEverything();
}

这是一个完整的代码示例,按照要求显示了我的意思。 循环是为了确保等待的代码不会立即完成。两个测试函数的输出相同。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestApplication
{
    public class Program
    {
        static void Main(string[] args)
        {
            Program test = new Program();
            Task firstTest = test.StartMultipleAwaitTest();
            firstTest.Wait();
            test.StartSingleAwaitTest();
            Console.ReadLine();
        }

        public async Task StartSingleAwaitTest() 
        {
            Console.WriteLine("\nStarting second test");
            await FirstTask();
            SecondTask();
            ThirdTask();
            Console.WriteLine("End");
        }

        public async Task StartMultipleAwaitTest() 
        {
            Console.WriteLine("Start");
            await FirstTask();
            await SecondTask();
            await ThirdTask();
            Console.WriteLine("End");
        }

        public async Task FirstTask() 
        {
            Console.WriteLine("Start First task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Firt task");
        }

        public async Task SecondTask()
        {
            Console.WriteLine("Start Second task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Second task");
        }

        public async Task ThirdTask()
        {
            Console.WriteLine("Start Third task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Third task");
        }
    }
}

the first await starts a second thread and returns control to the calling thread.

没有。 await 最强调的是 启动第二个线程。我有一个博客 post 描述 what await does do in detail

Output is identical for both test functions.

输出相同的原因是因为在这两种情况下,所有函数 运行 都是同步的。注意你的编译器警告;在这种情况下,编译器将对您的 FirstTask 方法(和朋友)发出警告,说明这些方法将 运行 同步。

StartMultipleAwaitTest 测试中实际发生的是,在 await 甚至检查 Task 之前,方法已经 运行 完成。同样,在 StartSingleAwaitTest 测试中,方法也在返回 StartSingleAwaitTest.

之前同步 运行 完成

更真实的测试(即在异步方法中进行异步工作)将为您提供更真实的结果:

public async Task FirstTask() 
{
  Console.WriteLine("Start First task");
  await Task.Delay(TimeSpan.FromSeconds(2));
  Console.WriteLine("End Firt task");
}

public async Task SecondTask()
{
  Console.WriteLine("Start Second task");
  await Task.Delay(TimeSpan.FromSeconds(3));
  Console.WriteLine("End Second task");
}

public async Task ThirdTask()
{
  Console.WriteLine("Start Third task");
  await Task.Delay(TimeSpan.FromSeconds(2));
  Console.WriteLine("End Third task");
}