C# 在已拆分的上下文上调用wait时是否有开销?

C# 在已拆分的上下文上调用wait时是否有开销?,c#,multithreading,asynchronous,async-await,overhead,C#,Multithreading,Asynchronous,Async Await,Overhead,编辑:我的问题没有真正意义,因为我误解了任务是如何工作的。我认为斯蒂芬·克利里的回答是可以接受的,因为它为我指明了学习错误的方向 我经常看到这样的代码: public async Task DoSomething(){ await DoSomethingElse(); await DoSoManyThings(); await DoEverything(); } 现在我看到的是,第一个wait启动第二个线程,并将控制权返回给调用线程。当等待完成时,调用第二个等待。

编辑:我的问题没有真正意义,因为我误解了任务是如何工作的。我认为斯蒂芬·克利里的回答是可以接受的,因为它为我指明了学习错误的方向

我经常看到这样的代码:

public async Task DoSomething(){
     await DoSomethingElse();
     await DoSoManyThings();
     await DoEverything();
}
现在我看到的是,第一个wait启动第二个线程,并将控制权返回给调用线程。当等待完成时,调用第二个等待。这就是我可能感到困惑的地方。第二个等待拆分上下文/创建新线程,另一个线程消失(返回调用方)。这有开销吗?如果是,多少钱?为了避免无缘无故地创建新线程,我的代码最好如下所示:

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");
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间测试应用程序
{
公共课程
{
静态void Main(字符串[]参数)
{
程序测试=新程序();
Task firstTest=test.StartMultipleAwaitTest();
firstTest.Wait();
test.startGleatWaitTest();
Console.ReadLine();
}
公共异步任务StartGleatWaitTest()
{
Console.WriteLine(“\n开始第二次测试”);
等待第一个任务();
第二个任务();
第三任务();
控制台。写入线(“结束”);
}
公共异步任务StartMultipleAwaitTest()
{
控制台写入线(“开始”);
等待第一个任务();
等待第二个任务();
等待第三个任务();
控制台。写入线(“结束”);
}
公共异步任务FirstTask()
{
Console.WriteLine(“启动第一个任务”);
对于(int i=0;i<10000000;i++){
Console.WriteLine(“结束第一个任务”);
}
公共异步任务SecondTask()
{
Console.WriteLine(“启动第二个任务”);
对于(int i=0;i<10000000;i++){
Console.WriteLine(“结束第二个任务”);
}
公共异步任务ThirdTask()
{
Console.WriteLine(“启动第三个任务”);
对于(int i=0;i<10000000;i++){
Console.WriteLine(“结束第三个任务”);
}
}
}
第一个等待启动第二个线程,并将控制权返回给调用线程

不。
wait
最强调的是不启动第二个线程。我有一篇博客文章描述

两个测试功能的输出相同

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

StartMultipleAwaitTest
测试中实际发生的情况是,在
await
甚至检查
任务之前,这些方法已经运行到完成。类似地,在
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");
}

如果DoEveryThing需要DoSoManyThings()的输出,则第二种方法可能不起作用。是的,有开销,但最小。每个程序和进程都有一些开销,线程的开销大致相同。根据我的理解,我的两个代码示例应该以完全相同的方式工作。也就是说,在第1个函数完成之前从不调用第2个函数,在第2个函数完成之前从不调用第3个函数。您只是猜测开销是相同的,您有什么原因/来源吗?“第一个等待启动第二个线程并将控制权返回给调用线程”——仅仅因为某个线程是
异步的,这并不意味着它创建了一个新线程。假设所调用的方法没有变化,并且它们确实是异步的,那么这两个示例的工作方式不同;在第二种情况下,由
DoSoManyThings()
启动的异步操作完成之前,将调用
DoEverything()
方法,而在第一种情况下,直到完成之后才会调用它。我也不知道“拆分上下文”是什么意思;假设为非默认同步上下文,则每个
wait
将在操作完成时返回到原始上下文。无论如何,你的问题太宽泛了。请将您的场景缩小到您可以提供的范围,以清楚地显示您的要求。添加了完整的示例。我之所以说拆分上下文,是因为新线程是在新上下文上运行的,尽管这可能不是问我问题的最清晰的方式。谢谢你的回答!我对任务的理解有一些重大缺陷,你的博客文章和其他一些来源帮助我澄清了这一点。我已经将你的答案标记为正确,即使它没有真正回答我的问题,尽管这是因为我的问题没有真正意义!