简体   繁体   English

异步/等待示例

[英]Async / Await by example

Ok, I guess I'm almost there on understanding all the fuzz on async / await and multithreading.好的,我想我几乎已经了解了async / await和多线程的所有模糊。 I understand that asynchronous is about tasks and multithreading is about workers.我知道异步是关于任务的,而多线程是关于工人的。 So you can have different tasks running on the same thread ( this answer does a great job explaining it).所以你可以在同一个线程上运行不同的任务(这个答案很好地解释了它)。

So I made a small programs in order to see the magic happening and I got a little confused:所以我做了一个小程序来看看神奇的发生,我有点困惑:

public class Program
{
    public static async Task Main(string[] args)
    {
        var task = ToastAsync();
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Cleaning the kitchen...");
        await task;
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Take the toast");
    }

    public async static Task ToastAsync()
    {
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Putting the toast");
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Setting a timer");
        await Task.Delay(2000);
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Toast is ready");
    }
}

Before running this program for the first time, I expected it to run on a single thread.在第一次运行这个程序之前,我希望它在单线程上运行。 Like the answer I linked above, I expected that this was the equivalent of "cleaning the kitchen while the toast's timer is running".就像我上面链接的答案一样,我预计这相当于“在吐司计时器运行时清洁厨房”。 The results though contradict it:结果虽然矛盾:

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[4] Take the toast

The above result doesn't make much sense to me.上述结果对我来说没有多大意义。 What is really happening?到底发生了什么? It seems part of the function is being executed in one thread and then, when it hits an await point it handles the execution to another thread...?似乎该函数的一部分正在一个线程中执行,然后,当它遇到await点时,它会将执行处理到另一个线程......? I didn't even know this was possible D:我什至不知道这是可能的 D:

Furthermore, I changed the above example a bit.此外,我稍微改变了上面的例子。 In the main function, instead of await task;在main函数中,代替await task; I used task.Wait() .我使用了task.Wait() And then the results changed:然后结果发生了变化:

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[1] Take the toast

Now this looks more like the example.现在这看起来更像示例。 It is like the timer on the toast worked as a different "cooker" though.就像吐司上的计时器就像一个不同的“炊具”一样。 But why is it different from using await ?但是为什么它与使用await不同? And is there a way of getting asynchronous task fully in a single thread?有没有办法在单个线程中完全获取异步任务? I mean, by having Toast is ready on thread 1 as well?我的意思是,让Toast is readythread 1Toast is ready

ThanksAsync!谢谢异步!

The things to note are需要注意的是

  1. When you call ToastAsync it starts the Task Hot (even though you haven't called await ).当您调用ToastAsync它会启动Task Hot (即使您还没有调用await )。 Note : Starting a Task does not mean starting a thread... Which in-turn explains why "Cleaning the kitchen."注意:开始一个任务并不意味着开始一个线程......这反过来解释了为什么“打扫厨房”。 is behind "Putting the toast")在“吐司”后面)

  2. The async method will run until hitting its first await keyword, and yields control back to the caller. async方法将一直运行直到命中它的第一个await关键字,并将控制权交还给调用者。

  3. Since there is no SynchronizationContext in a Console App .由于Console App 中没有SynchronizationContext The Compiler sees no need to create a Continuation on the calling thread , which in-turn explains why "Take the toast" is on the same thread as "Toast is ready". Compiler 认为无需在调用线程上创建Continuation ,这反过来解释了为什么“Take the toast”与“Toast is ready”在同一线程上。

Note : If you clean the kitchen after you make a mess, you don't have to clean it beforehand注意:如果你把厨房弄得一团糟,你不必事先打扫干净

From comments来自评论

I understand then that an await will always take a thread from thread pool to run the the method (this is really blowing my mind) therefore it is basically impossible to have an async / await single threaded我明白,await 总是会从线程池中取出一个线程来运行该方法(这真的让我大吃一惊)因此基本上不可能有 async/await 单线程

The Async and Await pattern isn't about multi-threading per-se, it's about scalability and IO bound workloads, and/or UI responsiveness (in UI frameworks). Async 和 Await 模式本身与多线程无关,它与可伸缩性和 IO 绑定工作负载和/或UI响应性(在UI框架中)有关。

Take a look at some of Stephen Cleary's articles on the subject:看看 Stephen Cleary 关于这个主题的一些文章:

Async and Await - Stephen Cleary 异步和等待 - Stephen Cleary

If you run the same code from an event of a Windows Form you'll get the expected results:如果您从 Windows 窗体的事件中运行相同的代码,您将获得预期的结果:

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[1] Toast is ready
[1] Take the toast

This is because the await by default restores the context after the awaiting, but this has a cost because it's an extra thing to do.这是因为默认情况下await在等待后恢复上下文,但这会产生成本,因为这是一件额外的事情。 If you don't need the context restoration you can configure the await like this:如果您不需要上下文恢复,您可以像这样配置等待:

await Task.Delay(2000).ConfigureAwait(false);

...and you'll see the same output as the Console Application. ...您将看到与控制台应用程序相同的输出。

Keep in mind that awaiting is not about doing things concurrently, it is about keeping the UI responsive.请记住,等待不是并发做事,而是保持 UI 响应。 You want to be able to keep receiving new orders for toasts, while the toasts from previous orders are cooking.您希望能够继续收到新的吐司订单,而之前订单的吐司正在烹饪。

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

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