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 :
Is there a difference between the two implementations (in the concept of parallelism)?
What are the benefits of using async
and await
keywords if I can just create a task and wait for it to finish?
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.
I'll attempt to answer the questions directly:
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.
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.
async / await cleans up the masses of complicated code that would over utilize Task.ContinueWith.ContinueWith.ContinueWith and so on.
From a coding perspective it is much harder to visualize, debug and maintain Task.ContinueWith, including the associated exception handling that must come with it.
So, await came along, and gave us this
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";
});
}
Which is pretty much equivalent to:
public static void Main()
{
Launch();
}
public static async void Launch()
{
Console.WriteLine("Hello!! welcome to task application");
Console.ReadKey();
return Task.Factory.StartNew(() => GetMessage())
.ContinueWith((t) =>
{
Console.WriteLine(t.Result)
Console.ReadKey();
});
}
public static Task<string> GetMessage()
{
return Task.Factory.StartNew<string>(() =>
{
return "Good Job";
});
}
You can see from the example that everything after GetMessage() is contained in a ContinueWith, however the method returns the task as soon as it is created. So it is returning to the calling method.
Here we need to wait on that Task, otherwise the program will continue to exit:
Launch().Wait();
Not having to write ContinueWith() means our code becomes more readable, especially in the cases of when we have to chain multiple await blocks together in a single method, it will "read" fine.
Also as mentioned before, better exception handling is dealt with the await examples, otherwise we would have to use TPL methods to deal with exceptions, which can also over complicate a code base.
With regards to both of your examples, they are not really equivalent, so you can't really judge one over the other. However, async/await is equivalent to constructing Tasks/ContinueWith.
I see async/await as an evolution of TPL into the actual language itself. A type of syntactical sugar.
链接地址: http://www.djcxy.com/p/13926.html上一篇: Ruby Fibers可以并行吗?
下一篇: 使用异步和等待关键字的好处