为什么多个等待需要像 Task.WhenAll() 一样的时间 [英] Why Multiple await take same time like Task.WhenAll()

查看:29
本文介绍了为什么多个等待需要像 Task.WhenAll() 一样的时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道当你有一个任务列表时,建议在多个 await 上使用 await Task.WhenAll(),因为 Task.WhenAll() 处理异常.但是,根据我对async,await"工作方式的理解,我想知道为什么下面的代码块具有相同的执行时间:

I understand that when you have a list of tasks, it's recommended to use await Task.WhenAll() over multiple await, due to the way that Task.WhenAll() handles exceptions. However, from my understanding of the way that "async,await" works, I wonder why the below code blocks have the same execution time:

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);
}

这个block执行需要10秒,这个block也是一样的:

This block will take 10 seconds to be executed, which is the same for this one:

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 秒,因为 await 的列表将依次执行,因为这是 Microsoft 在 MSDN 中解释的 async,await 方法.我在这里缺少什么?它是编译器优化的东西吗?有人能解释一下幕后发生了什么吗?

From my understanding, the first block should take 22 seconds, because the list of await will get executed in order one by one, as this is how async,await explained by Microsoft in MSDN. What I'm missing here? Is it something optimised the the compiler? Could someone explain what's going under the hood?

推荐答案

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

Task.Delay internally uses a timer to notify the program when it should continue. The timer starts as soon as you call Task.Delay. In both cases you start the tasks one after another as you store the tasks in variables, only to await them later. While awaiting any of them, the timers are still going in the background and because they started more or less at the same time, they finish when the one with the longest delay finishes

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");

所有 First/Second/Third finished 消息几乎同时显示,在 10 秒后.一些修改后你可以看到变化:

All of the First/Second/Third finished messages show up almost at the same time, after 10s. You can see a change after some modification:

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");

现在 First finished 在 5s 后显示,Second finished 再过 2s 和 Third finished 再过 3s.

Now First finished shows up after 5s, Second finished after another 2s and Third finished after another 3s.

要获得所需的结果,您必须按顺序调用这些函数并 await 就在那里,就像这样:

To get the desired result you'd have to call the functions sequentially and await each one right there, like this:

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.Delay 本身,使代码更简单(对您和编译器而言)


The SleepForTime function is a perfect candidate for some style improvements - use the suffix Async to indicate that it should be used in asynchronous code and you can return the task returned from Task.Delay itself making the code a little simpler (for you and the compiler)

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

这篇关于为什么多个等待需要像 Task.WhenAll() 一样的时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆