其他分享
首页 > 其他分享> > 为何多次等待需要像Task.WhenAll()一样的时间

为何多次等待需要像Task.WhenAll()一样的时间

作者:互联网

我了解,当您有任务列表时,由于Task.WhenAll()处理异常的方式,建议在多个await中使用await Task.WhenAll().但是,从我对“异步,等待”工作方式的理解,我想知道为什么下面的代码块具有相同的执行时间:

static void Main(string[] args)
{
    MainAsync(args).GetAwaiter().GetResult();
    Console.ReadLine();
}

static async Task MainAsync(string[] args)
{
    Console.WriteLine("Starts :" + DateTime.Now.ToLongTimeString());
    var firstTask = SleepForTime(10000);
    var secondTask = SleepForTime(7000);
    var thirdTask = SleepForTime(5000);

    await firstTask;
    await secondTask;
    await thirdTask;

    Console.WriteLine("Done :" + DateTime.Now.ToLongTimeString());

    Console.ReadLine();
}

public static async Task SleepForTime(int seconds)
{
    await Task.Delay(seconds);
}

该块将花费10秒执行,这与该块相同:

static void Main(string[] args)
{
    MainAsync(args).GetAwaiter().GetResult();
    Console.ReadLine();
}

static async Task MainAsync(string[] args)
{
    Console.WriteLine("Starts :" + DateTime.Now.ToLongTimeString());
    var firstTask = SleepForTime(10000);
    var secondTask = SleepForTime(7000);
    var thirdTask = SleepForTime(5000);

    await Task.WhenAll(firstTask, secondTask, thirdTask);

    Console.WriteLine("Done :" + DateTime.Now.ToLongTimeString());

    Console.ReadLine();
}

public static async Task SleepForTime(int seconds)
{
    await Task.Delay(seconds);
}

据我了解,第一个块应该花费22秒,因为等待列表将按一个顺序执行,因为这是Microsoft在MSDN中解释的异步等待方式.我在这里想念的是什么?是否对编译器进行了优化?有人可以解释幕后情况吗?

解决方法:

Task.Delay内部使用计时器通知程序何时应继续.只要调用Task.Delay,计时器就会启动.在这两种情况下,您都将任务存储在变量中时一个接一个地启动任务,只是稍后再等待.在等待它们中的任何一个时,计时器仍在后台运行,并且由于它们或多或少地同时启动,因此它们会在延迟时间最长的计时器结束时结束

var firstTask = SleepForTime(10000);
var secondTask = SleepForTime(7000);
var thirdTask = SleepForTime(5000);  

// All of the tasks are already started
Console.WriteLine("Start");
await firstTask;                       //this finishes after ~10s
Console.WriteLine("First finished");
await secondTask;                      //this finishes immediately
Console.WriteLine("Second finished");
await thirdTask;                       //this also finishes immediately
Console.WriteLine("Third finished");

所有的第一/第二/第三完成消息都会在10秒后几乎同时显示.进行一些修改后,您可以看到更改:

var firstTask = SleepForTime(5000);
var secondTask = SleepForTime(7000);
var thirdTask = SleepForTime(10000);  

// All of the tasks are already started
Console.WriteLine("Start");
await firstTask;                      //this finishes after ~5s
Console.WriteLine("First finished");
await secondTask;                     //this finishes after 2 more seconds
Console.WriteLine("Second finished");
await thirdTask;                      //this finishes after 3 more seconds
Console.WriteLine("Third finished");

现在,第一完成出现在5s之后,第二完成出现在另外2s之后,第三完成出现在另外3s之后.

为了获得理想的结果,您必须依次调用这些函数并在那里等待每个函数,如下所示:

Console.WriteLine("Start");
await SleepForTime(10000);            //this finishes after 10s
Console.WriteLine("First finished");
await SleepForTime(7000);             //this finishes after 7s
Console.WriteLine("Second finished");
await SleepForTime(5000);             //this finishes after 5s
Console.WriteLine("Third finished");

SleepForTime函数是进行某些样式改进的理想选择-使用后缀Async表示应在异步代码中使用它,并且您可以返回Task返回的任务.延迟本身会使代码更简单(对于您和编译器而言) )

public static Task SleepForTimeAsync(int seconds)
{
    return Task.Delay(seconds);
}

标签:asynchronous,async-await,task,console-application,c
来源: https://codeday.me/bug/20191025/1929854.html