简体   繁体   English

async/await,如何正确使用

[英]async / await, how to use properly

I am trying to study c# async/await, all the tutorials I found are the same stuff and I can't really understand anything, for instance, why this code doesn't work?我正在尝试研究 c# async/await,我发现的所有教程都是相同的东西,我什么都不懂,例如,为什么这段代码不起作用? Could you please explain the how's and why's of async/await or give some useful links to truly understand given that I don't have experience with it.您能否解释一下异步/等待的方式和原因,或者提供一些有用的链接来真正理解,因为我没有这方面的经验。

class Program
    {
        static void Main(string[] args)
        {
            Waiter();
        }

        public static async void Waiter()
        {
            await HeavyStuff();
            Console.WriteLine("1");
        }

        public static async Task HeavyStuff()
        {
            await Task.Run(() => {
                Thread.Sleep(1000);
                Console.WriteLine("2");
            });
        }
    }

await the Waiter() in the Main().在 Main() 中等待 Waiter()。 Otherwise it will call Waiter(), but Main() will go on without waiting for Waiter() to finish.否则它将调用 Waiter(),但 Main() 将 go 打开而不等待 Waiter() 完成。 That is called "fire and forget".这就是所谓的“一劳永逸”。 Main() will finish and the program ends before Waiter() is done. Main() 将完成并且程序在 Waiter() 完成之前结束。

class Program
{
    static async Task Main(string[] args)
    {
        await Waiter();
    }

    public static async Task Waiter()
    {
        Console.WriteLine("1");
        await HeavyStuff();
        Console.WriteLine("4"); // this will be instantly shown after "3"
    }

    public static async Task HeavyStuff()
    {
        Console.WriteLine("2");  // this will be instantly shown after "1"
        await Task.Delay(1000);  // short version of Task.Run(() => Thread.Sleep(1000))
        Console.WriteLine("3");  // this will be shown after 1 second
    }
}

A fire forget version without async Main.没有异步 Main 的火忘记版本。 In this version we prevent the Main from finishing (= ending the Program) before Waiter can finish.在这个版本中,我们阻止 Main 在 Waiter 完成之前完成(= 结束程序)。

class Program
{
    static void Main(string[] args)
    {
        Waiter();
        Thread.Sleep(2000);  // this gives Waiter() time to finish
    }

    public static async Task Waiter()
    {
        Console.WriteLine("1");
        await HeavyStuff();
        Console.WriteLine("4");
    }

    public static async Task HeavyStuff()
    {
        Console.WriteLine("2");
        await Task.Delay(1000);
        Console.WriteLine("3");
    }
}

I would urge you to read a blog post by Stephen Cleary for a rather comprehensive explanation of what the point of async/await is.我强烈建议您阅读 Stephen Cleary 的博客文章,以获得关于 async/await 的意义的相当全面的解释。

To your question specifically though, the use of async in the method signature prompts the compiler to create a state machine.但是,特别针对您的问题,在方法签名中使用async会提示编译器创建 state 机器。 You must put the async keyword in the method in order to enable the use of await within the method body (as you likely found when writing Waiter() and HeavyStuff() ).您必须将async关键字放在方法中,以便在方法主体中启用await (正如您在编写Waiter()HeavyStuff()时可能发现的那样)。

What ultimately happens here is that when you call Waiter from Main, it does actually call the Waiter method, but because you're not awaiting the result of the call, it treats it as a "fire-and-forget".这里最终发生的是,当您从 Main 调用 Waiter 时,它确实调用了 Waiter 方法,但是因为您没有等待调用的结果,所以它将其视为“即发即弃”。 As such, you experience the program closing.因此,您会体验到程序关闭。

Similarly, while Waiter() awaits HeavyStuff() (if Waiter() were awaited from Main() ), the program will wait for that method to return before showing the "1" on the console.同样,当Waiter()等待HeavyStuff()时(如果 Waiter() 是从Main()等待的),程序将等待该方法返回,然后在控制台上显示“1”。

The blog post above covers this, but you'll likely not want to return void from Waiter() because that's typically used for event handling where there's nothing actually waiting on the result of the method.上面的博客文章涵盖了这一点,但您可能不想从Waiter()返回 void ,因为这通常用于事件处理,实际上没有任何东西在等待方法的结果。 While you're not returning a value with your method, you are awaiting it, so it's better practice to return Task instead.虽然您没有使用方法返回值,但您正在等待它,因此最好改为返回 Task。

Since C# 7.1, you've been allowed to use the async keyword in your Main() entry point, thus your code should be as follows:自 C# 7.1 起,您已被允许在Main()入口点中使用async关键字,因此您的代码应如下所示:

class Program
{
    static async Task Main(string[] args)
    {
        await Waiter();
    }

    public static async Task Waiter()
    {
        await HeavyStuff();
        Console.WriteLine("1");
    }

    public static async Task HeavyStuff()
    {
        await Task.Delay(1000);
        Console.WriteLine("2");
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM