-1

As reading C# in Depth of Jon Skeet, I have come across the following expression.

You’re setting label.Text at the start and end of the method, so it’s reasonable to assume that both of those statements are executed on the UI thread, and yet you’re clearly not blocking the UI thread while you wait for the web page to download. The trick is that the method returns as soon as it hits the await expression.

When I click the button, I expect that Debug.WriteLine("end method " + DateTime.Now.ToString("ss.fffff")); runs and prints out without waiting for the website's response. However, it prints out after the response is received. Doesn't it conflict with the bold text part in the quotation? I have tested it by slowing down Visual Studio's connection speed by NetBalancer. The Debug.Writeline(..) part doesn't print out immediately after hitting await as opposed to the saying. Both the UI's output and that of debug yield same nanosecs. Where do I do mistake? I must be wrong since he cannot be mistaken (:

public class AsyncIntro : Form
{
    private static readonly HttpClient Client = new HttpClient();
    private readonly        Label      _label;
    private readonly        Button     _button;

    public AsyncIntro()
    {
        _label = new Label
                {
                    Location = new Point(10, 30),
                    Text     = "Length"
                };
        _button = new Button
                 {
                     Location = new Point(10, 60),
                     Text     = "Click"
                 };
        _button.Click += DisplayWebSiteLength;
        AutoSize     =  true;
        Controls.Add(_label);
        Controls.Add(_button);
    }

    public sealed override bool AutoSize { get; set; }
    

    private async void DisplayWebSiteLength(object sender, EventArgs e)
    {
        _label.Text = "Fetching...";
        var text = await  Client.GetStringAsync("http://csharpindepth.com");
        _label.Text = text.Length.ToString() + "  " + DateTime.Now.ToString("ss.fffff");
        Debug.WriteLine("end method " + DateTime.Now.ToString("ss.fffff"));
    }

    private static void Main()
    {
        Application.Run(new AsyncIntro());
    }
}
  • 4
    Since your `Debug.WriteLine` is *after* the `await` it cannot be executed before that is finished – UnholySheep Dec 11 '20 at 14:07
  • That's because it's after the `await`, everything after the `await` happens after the response from the website is returned. Jon literally says that's why the second label update happens after the web call. – juharr Dec 11 '20 at 14:07
  • 2
    "the method returns as soon as it hits the await expression." - which means it's **not** continuing to run code *inside* the method and therefore not returning by "falling off the end" of the method's code. – Damien_The_Unbeliever Dec 11 '20 at 14:08
  • async/await basically gets turned into a state machine where code before the await gets run and stuff after the await is run as a continuation of the awaited task. – juharr Dec 11 '20 at 14:10
  • 1
    You wouldn't be surprised if you saw a `return` statement in a method and no further code in the method executed. Think of `await` as a conditional `return` that also supports the remainder of the method being executed later. – Damien_The_Unbeliever Dec 11 '20 at 14:10
  • @Damien_The_Unbeliever thanks a lot sir – Soner from The Ottoman Empire Dec 11 '20 at 15:18
  • I also recommend reading [Async and Await](https://blog.stephencleary.com/2012/02/async-and-await.html); I try to cover What You Need To Know without going too in-depth all at once. – Stephen Cleary Dec 12 '20 at 01:25

1 Answers1

0

When I click the button, I expect that Debug.WriteLine("end method " + DateTime.Now.ToString("ss.fffff")); runs and prints out without waiting for the website's response.

Why would you expect that? You clearly tell the compiler to (a)wait for the server response before continuing execution.

Doesn't it conflict with the bold text part in the quotation?

No. Behind the scene the method is transformed into a statemachine. In simpler terms the method is split into two parts:

  1. Everything up to the await statement
  2. Everything after the await statement

When the GetStringAsync call is made, the first method asks the returned task "when your done, please call the second method, and make sure you do it on the main thread". The task obliges when it completes, and puts a message on the message queue for the UI thread to run the second method.

JonasH
  • 28,608
  • 2
  • 10
  • 23