Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Benefits of using async and await keywords

I'm new in the use of asynchronous methods in C#. I have read that these keywords async and await help to make the program more responsive by asynchronizing some methods. I have this snippet :

First Way

    public static void Main()
    {
        Console.WriteLine("Hello!! welcome to task application");
        Console.ReadKey();
        Task<string> ourtask = Task.Factory.StartNew<string>(() =>
        {
            return "Good Job";
        });
        ourtask.Wait();
        Console.WriteLine(ourtask.Result);
        Console.ReadKey();
    }

Second Way

 public static void Main()
        {
            Launch();
        }
        public static async void Launch()
        {
            Console.WriteLine("Hello!! welcome to task application");
            Console.ReadKey();
            Console.WriteLine(await GetMessage());
            Console.ReadKey();
        }

        public static Task<string> GetMessage()
        {
            return Task.Factory.StartNew<string>(() =>
                {
                    return "Good Job";
                });
        }

I need to know :

  1. Is there a difference between the two implementations (in the concept of parallelism)?

  2. What are the benefits of using async and await keywords if I can just create a task and wait for it to finish?

like image 737
Lamloumi Afif Avatar asked Mar 03 '15 20:03

Lamloumi Afif


3 Answers

Say you have a single border checkpoint. Each car can pass it one-by-one to have customs take a look at their car to see if they're not smuggling any Belgian chocolate.

Now assume that you are in line in your Volkswagen Beetle where you can barely fit in and before you is a 24-wheel monstertruck. You are now stuck behind this behemoth for a long time until customs are done searching through it all before they can move on to you who they basically just have to pat down to tell you you're good to go.

In order to combat this efficiency, our good friends at the border patrol have an idea and install a second checkpoint. Now they can pass in twice as many people and you can just take that one instead of waiting behind the monstertruck!

Problem solved, right? Not exactly. They forgot to create a second road that leads to that checkpoint so all traffic still has to go over the single lane, resulting in the truck still blocking the Beetle.

How does this relate to your code? Very easy: you're doing the same.

When you create a new Task you essentially create that second checkpoint. However when you now synchronously block it using .Wait(), you are forcing everyone to take that single road.

In the second example you use await which creates that second road and allows your car to be handled simultaneously with the truck.

like image 67
Jeroen Vannevel Avatar answered Sep 24 '22 02:09

Jeroen Vannevel


Going with the border checkpoint analogy, I would say:

Sync border employees

You have 4 incoming lanes and 2 officers. The officer handling the incoming monstertruck, Jack, does not know the exact rules for monstertrucks, so he calls the office. Now, if he works sync, he stays on the phone waiting for a response. So he is not able to handle anything else - his colleague Mary will have to do that.

Fortunately Mary works parallel, so she can process the 3 unblocked lanes in the meantime. However, because she also works sync, she only one processes one vehicle at a time. So when she has to check the rules for a motorcycle with a cheetah in the sidecar, she has to call the main office and also stays on the phone for the answer.

Now we have two lanes blocked by pending jobs, and two lanes blocked because there are no employees.

Async border employees

Now if Jack works async - he will not hold the line waiting for a response. Instead he hangs up, and goes to the second lane, and processes another car, while waiting for the main office to return his call. Because the second lane is a very nervous lady with a stutter, this is taking him quite some time.

But fortunately Mary now also works async, and when she finished processing her second vehicle (or paused it, because she had to check on the cheetah), she can take the return call from the office on the monstertruck. So she can finish processing the monstertruck.
But of course the monstertruck is not gone right after she finished - the driver has log his time spent at the checkpoint. Fortunately Mary still works parallel, so she can start processing a car in another lane.

Costs

Then one day, the Burning Man festival is starting, and a lot of unusual vehicles arrive at the border. These all take a lot of calls to the office, therefore blocking all 4 lanes. So Jack and Mary can only sit around waiting for return calls, while the line of vehicles is growing.

Fortunately, land is cheap in this area, so their boss decides to add 4 more lanes. While some of these extra lanes are also blocked waiting for return calls from the office, at least Jack and Mary keep busy, and don't have to sit and wait for calls. Of course their boss can consider hiring some extra employees to reduce the traffic jam, but he knows they will need housing and training, and the festival will be over soon, so he leaves it as it is...

Recap

Leaning towards ASP.Net:

  • lanes (e.g. connections) are cheap, and can be scaled easily (and you should probably increase the connection limit and queue size in IIS for async, e.g. see introduction-reference below)
  • employees (threads) are more expensive (e.g. see introduction-reference below))
  • 'slow' parts of a job (e.g. I/O, or remote http-requests), should not block your expensive employees (i.e. one should use async)
  • NB: jobs may change employees (pun intended), so don't keep data with your employees. E.g. Jack should not put monstertruck-papers in his pocket, because Mary may process it further - he should rather return it, or keep it in a job-dependent storage (don't store data within the thread, but rather in the HttpContext)

Literature

FWIW: I like this technical introduction from 2014 by Stephen Cleary.

like image 26
Yahoo Serious Avatar answered Sep 24 '22 02:09

Yahoo Serious


I'll attempt to answer the questions directly:

  1. Neither of your examples (effectively) involves any parallelism. I see 2 main differences between them: 1) The first example will block a thread while the task runs on a second thread, which is pointless, and 2) the second example will exit early. As soon as await is encountered, control immediately returns to Main(), and since you're not waiting for the task returned from Launch() to complete, your program will exit at that point.

  2. The benefit of using async and await vs. waiting for a task to complete is that await does not block the current thread while that task is running. Under the hood, anytime the compiler encounters an await, it effectively rewrites the rest of that method as a callback that will be called upon completion of the task. That frees up the current thread to do other things while the task is running, such as respond to user input in a client app or service other requests in a Web application.

Frankly, this is not a good example to demonstrate the benefits of async/await. You're basically saying that you want to do CPU-bound work, and you don't want to do anything else until that work is done. You may as well do that synchronously. Asynchrony really shines when doing I/O-bound work, such as making a call across the network (using a properly implemented asynchronous library such as HttpClient), because you're not simply trading one thread for another as in your second example; there literally is no thread being consumed by that I/O-bound work.

As others have alluded to, parallelism is another topic entirely. While async/await can be useful contructs to help you achieve it, there's a bit more involved, and in my opinion you'd be better served to get a firm grasp on the thread-freeing benefits before "moving on" to parallelism.

Also as others have alluded to, this is a big topic and I highly recommend you check out some of the great resources out there. Since I already referenced Stephen Cleary's blog, I'll go ahead and give it a full plug - his async/await intro and subsequent posts are an excellent primer on the subject.

like image 38
Todd Menier Avatar answered Sep 22 '22 02:09

Todd Menier