为什么简单的 await Task.Delay(1) 支持并行执行? [英] Why a simple await Task.Delay(1) enables parallel execution?

查看:67
本文介绍了为什么简单的 await Task.Delay(1) 支持并行执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想问一个关于下面代码的简单问题:

I would like to ask simple question about code bellow:

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

static async Task MainAsync()
{
    Console.WriteLine("Hello World!");

    Task<int> a = Calc(18000);
    Task<int> b = Calc(18000);
    Task<int> c = Calc(18000);

    await a;
    await b;
    await c;

    Console.WriteLine(a.Result);
}

static async Task<int> Calc(int a)
{
    //await Task.Delay(1);
    Console.WriteLine("Calc started");

    int result = 0;

    for (int k = 0; k < a; ++k)
    {
        for (int l = 0; l < a; ++l)
        {
            result += l;
        }
    }

    return result;
}

此示例以同步方式运行 Calc 函数.当行 //await Task.Delay(1); 被取消注释时,Calc 函数将以并行方式执行.

This example runs Calc functions in synchronous way. When the line //await Task.Delay(1); will be uncommented, the Calc functions will be executed in a parallel way.

问题是:为什么通过添加简单的等待,Calc 函数然后是异步的?我知道异步/等待对要求.我问的是在函数的开头添加简单的 await Delay 时真正发生了什么.然后整个 Calc 函数被识别为在另一个线程中运行,但为什么呢?

The question is: Why, by adding simple await, the Calc function is then async? I know about async/await pair requirements. I'm asking about what it's really happening when simple await Delay is added at the beginning of a function. Whole Calc function is then recognized to be run in another thread, but why?

编辑 1:

当我向代码添加线程检查时:

When I added a thread checking to code:

static async Task<int> Calc(int a)
{
    await Task.Delay(1);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

    int result = 0;

    for (int k = 0; k < a; ++k)
    {
        for (int l = 0; l < a; ++l)
        {
            result += l;
        }
    }

    return result;
}

可以看到(在控制台中)不同的线程 ID.如果删除 await Delay 行,则所有 Calc 函数运行的线程 ID 始终相同.在我看来,它证明了 await 之后的代码(可以)在不同的线程中运行.这就是代码更快的原因(我当然认为).

it is possible to see (in console) different thread id's. If await Delay line is deleted, the thread id is always the same for all runs of Calc function. In my opinion it proves that code after await is (can be) runned in different threads. And it is the reason why code is faster (in my opinion of course).

推荐答案

了解 async 方法的工作原理很重要.

It's important to understand how async methods work.

首先,它们开始在同一个线程上同步运行,就像其他所有方法一样.如果没有该 await Task.Delay(1) 行,编译器将警告您该方法将是完全同步的.async 关键字本身不会使您的方法异步.它只是启用了 await 的使用.

First, they start running synchronously, on the same thread, just like every other method. Without that await Task.Delay(1) line, the compiler will have warned you that the method would be completely synchronous. The async keyword doesn't, by itself, make your method asynchronous. It just enables the use of await.

魔法发生在第一个 await 上,它作用于不完整的 Task.此时方法返回.它返回一个 Task,您可以使用它来检查方法的其余部分何时完成.

The magic happens at the first await that acts on an incomplete Task. At that point the method returns. It returns a Task that you can use to check when the rest of the method has completed.

因此,当您有 await Task.Delay(1) 时,该方法在该行返回,允许您的 MainAsync 方法移动到下一行并开始下次调用 Calc.

So when you have await Task.Delay(1) there, the method returns at that line, allowing your MainAsync method to move to the next line and start the next call to Calc.

Calc 的延续如何运行(await Task.Delay(1) 之后的所有内容)取决于是否存在同步上下文".例如,在 ASP.NET(不是 Core)或 UI 应用程序中,同步上下文控制延续的运行方式,并且它们将一个接一个地运行.在 UI 应用程序中,它将位于它开始的同一线程上.在 ASP.NET 中,它可能是一个不同的线程,但仍然一个接一个.因此,无论哪种情况,您都不会看到任何并行性.

How the continuation of Calc runs (everything after await Task.Delay(1)) depends on if there is a "synchronization context". In ASP.NET (not Core) or a UI application, for example, the synchronization context controls how the continuations run and they would run one after the other. In a UI app, it would be on the same thread it started from. In ASP.NET, it may be a different thread, but still one after the other. So in either case, you would not see any parallelism.

但是,因为这是一个控制台应用程序,它没有同步上下文,只要 Task.Delay(1) 完成.这意味着每个延续都可以并行发生.

However, because this is a console app, which does not have a synchronization context, the continuations happen on any ThreadPool thread as soon as the Task from Task.Delay(1) completes. That means each continuation can happen in parallel.

另外值得注意的是:从 C# 7.1 开始,您可以将 Main 方法设为 async,从而无需使用 MainAsync 方法:

Also worth noting: starting with C# 7.1 you can make your Main method async, eliminating the need for your MainAsync method:

static async Task Main(string[] args)

这篇关于为什么简单的 await Task.Delay(1) 支持并行执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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