📜 ⬆️ ⬇️

C # 5 - about async / await from the beginning

In the recently released Visual Studio 11 Beta, a new and main feature of the future C # 5 is built-in - asynchronous programming using async / await . About her already written quite a lot of articles, including those in Habré - for example, this series of articles . However, I didn’t understand for myself what the essence of the new syntax was until I tried it myself. This article is an attempt to structure oneself and fully understand this rather interesting tool and share the results with the community, telling about it a little differently. So let's go ...

Why do you need it?


C # actively developing language in each version of which there are interesting features that really simplify the writing of high-quality and understandable code. For example, Linq has greatly simplified writing filters for collections and sql queries in code. Now it's up to asynchrony.

And although the framework has already accumulated a fairly large number of ways to write multi-threaded code, from manually creating a stream to the visual component of BackgroundWorker, developing an asynchronous application requires writing a decent amount of infrastructure code that increases as the task becomes more complex. The main problem of this, in my opinion, is the need to change the state of the user interface from the background thread (which, as we know, cannot be done directly).

A new language design async / await solves this problem, allowing not only to run the task in the background thread and execute the code when it is completed, but it does it visually - the code looks almost like synchronous (including exception handling).
')

Meet: async / await


Generally speaking, keywords do not quite clearly reflect the essence, but as the developers explain it better, no one invented, therefore they are what they are. Like most entities in programming, the new construct is easiest to understand directly from the code:

//   private void OnButtonClick() { TextBox.Text = new WebClient().DownloadString("http://habrahabr.ru/"); } //   private async void OnButtonClick() { TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://habrahabr.ru/"); } 


And if in the synchronous version everything is simple and clear, then many questions arise with asynchronous. Strangely enough, let's start with the new method of the WebClient class - DownloadStringTaskAsync - this method returns Task <string> and in the new studio is marked as awaitable. The type of return value is the key moment in this whole story - looking ahead it’s worth saying that await can only work with functions returning Task and Task <T>.
UPD: as jack128 rightly noted in the comments, await works with any object that has the GetAwaiter () method, thanks to him for the correction.

So, the DownloadStringTaskAsync method creates a Task task and immediately returns it from a function, while in the background thread the page starts downloading from the requested url. We are free to work directly with the Task object, manually waiting for the result to be completed:

 private void OnButtonClick() { Task<string> task = new WebClient().DownloadStringTaskAsync("http://microsoft.com/"); task.Wait(); //     ,    TextBox.Text = task.Result; } 


This code, of course, remains synchronous, since we are mainly waiting for the background ...

We need a way to work as conveniently and asynchronously with a task (Task <T>), which remains the only “thread” that connects us to the background thread. And here await appears on the scene - it not only expands Task <T> to T, but also sets the rest of the method to “continuation”, which will be executed after the completion of the task and the most important thing in the same thread. In this case, the OnButtonClick () function will exit and the application will continue to work in its normal mode - responding to user actions.

As soon as the background thread finishes its work and returns the result, a “continuation” will be performed in the main thread , which in this case will set the page content in the text field.

It remains to deal with the async keyword - they need to mark the functions in which await will be used. Everything is simple, and most importantly, the compiler will see that you don’t forget about it - without letting you compile the program.

What it looks like in action


A function can have multiple awaits, which allows you to create asynchronous execution chains:

 private async void StartButtonClick(object sender, RoutedEventArgs e) { //       StartButton.IsEnabled = false; //   ,      //       TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://habrahabr.ru/"); StatusLabel.Content = "  ,  "; //           var result = await Task<string>.Factory.StartNew(() => { Thread.Sleep(5000); //   ... return " "; }); //     StatusLabel.Content = result; StartButton.IsEnabled = true; } 


What about exceptions? Since the developers have promised that the new syntax will be simple and close to synchronous, they could not ignore such an important problem of exception handling. As promised, exceptions thrown in the background thread can be processed using the classical syntax (as if there is no asynchrony):

 private async void StartButtonClick(object sender, RoutedEventArgs e) { try { TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://not-habrahabr.ru/"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } 


However, with exception handling there is one thing that needs to be understood - since all the code that comes after await is installed at the end and when it is executed is generally unknown, such exception handling will not work:

 //   !!! private void StartButtonClick(object sender, RoutedEventArgs e) { try { Download(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private async void Download() { TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://not-habrahabr.ru/"); } 


The Download function will return control as soon as the Task with the background thread is created, and then the exit from the StartButtonClick function will be executed ... and only later in the background thread will an exception be generated that the domain name cannot be resolved. A more detailed explanation can be read here .

Total


In the upcoming .Net 4.5 many classes will be added to support the new syntax - i.e. There will be many functions returning Task and Task <T>. And judging by the simplicity of the new syntax, it will be widely used, so a clear understanding of the new language constructions, their actions and scope is necessary.

To summarize, the async keyword does not cause the method to run in the background thread (as the name implies), but only notes that there is an await inside the method that works with Task and Task <T> in such a way that the rest of the method await will be executed after completing Task, but in the main thread.

Introducing a new syntax, Microsoft offers not just syntactic sugar, but a whole asynchronous programming pattern, including exception handling, interruption of the asynchronous function execution, and information on the progress of execution ... which are already beyond the scope of this article.

If there are any vague places, I will try to answer all the questions in the comments.

Source: https://habr.com/ru/post/139734/


All Articles