© Mikael Olsson 2020
M. OlssonC# 8 Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-5577-3_30

30. Asynchronous Methods

Mikael Olsson1 
(1)
HAMMARLAND, Finland
 

An asynchronous method is a method that can return before it has finished executing. Any method that performs a potentially long-running task, such as accessing a web resource or reading a file, can be made asynchronous to improve the responsiveness of the program. This is especially important in graphical applications, because any method that takes a long time to execute on the user interface thread will cause the program to be unresponsive while waiting for that method to complete.

The Async and Await Keywords

Introduced in C# 5.0, the async and await keywords allow asynchronous methods to be written with a simple structure that is similar to synchronous (regular) methods. The async modifier specifies that the method is asynchronous and that it can therefore contain one or more await expressions. An await expression consists of the await keyword followed by an awaitable method call.
class MyApp
{
  async void MyAsync()
  {
    System.Console.Write("A");
    await System.Threading.Tasks.Task.Delay(2000);
    System.Console.Write("C");
  }
}

This method will run synchronously until the await expression is reached, at which point the method is suspended and execution returns to the caller. The awaited task is scheduled to run in the background on the same thread. In this case the task is a timed delay that will complete after 2000 milliseconds. Once the task is complete, the remainder of the async method will execute.

Calling the async method from Main will output “A” followed by “B” and then “C” after the delay. Note the use of the ReadKey method here to prevent the console program from exiting before the async method has finished.
static void Main()
{
  new MyApp().MyAsync();
  System.Console.Write("B");
  System.Console.ReadKey();
}

Async Return Types

In C# 5.0 an async method can have one of three built-in return types: Task<T>, Task, and void. Specifying Task or void denotes that the method does not return a value, whereas Task<T> means it will return a value of type T. In contrast to void, the Task and Task<T> types are awaitable, so a caller can use the await keyword to suspend itself until after the task has finished. The void type is mainly used to define async event handlers, as event handlers require a void return type.

Custom Async Methods

In order to call a method asynchronously, it has to be wrapped in another method that returns a started task. To illustrate, the following method defines, starts, and returns a task which takes 2000 milliseconds to execute before it returns the letter “Y”. The task is here defined through the use of a lambda expression for conciseness.
using System.Threading.Tasks;
using System.Threading;
// ...
Task<string> MyTask()
{
  return Task.Run<string>( () => {
    Thread.Sleep(2000);
    return "Y";
  });
}
This task method can be called asynchronously from an async method. The naming convention for these methods is to append “Async” to the method name. The asynchronous method in this example awaits the result of the task and then prints it.
async void MyTaskAsync()
{
  string result = await MyTask();
  System.Console.Write(result);
}
The async method is called in the same way as a regular method, as can be seen in the following Main method. The output of the program will be “XY”.
static void Main()
{
  new MyApp().MyTaskAsync();
  System.Console.Write("X");
  System.Console.ReadKey();
}

Extended Return Types

C# 7.0 lessened the restriction on what return types an async method can have. This can be useful when an async method returns a constant result or is likely to complete synchronously, in which case the extra allocation of a Task object may become an undesired performance cost. The condition is that the returned type must implement the GetAwaiter method, which returns an awaiter object. To make use of this new feature, .NET provides the ValueTask<T> type, which is a lightweight value type that includes this method.

To give an example, the following PowTwo async method gives the result of the argument raised to the second power (a2). It executes synchronously if the argument is less than plus or minus ten and therefore returns a ValueTask<double> type in order to not have to allocate a Task object in such a case. Note that the Main method here has the async modifier. This is allowed as of C# 7.1 and is used for cases like this when the Main method calls an async method directly.
using System.Threading.Tasks;
public class MyAsyncValueTask
{
  static async Task Main()
  {
    double d = await PowTwo(10);
    System.Console.WriteLine(d); // "100"
  }
  private static async ValueTask<double> PowTwo(double a)
  {
    if (a < 10 && a > -10) {
      return System.Math.Pow(a, 2);
    }
    return await Task.Run(() => System.Math.Pow(a, 2));
  }
}

To use the ValueTask type, you need to add a NuGet package to your project. NuGet is a package manager providing free and open source extensions to Visual Studio. The package is added by right-clicking References in the Solution Explorer and choosing Manage NuGet Packages. Switch to the Browse tab and search for “Tasks” to find the System.Threading.Tasks.Extensions package. Select this package and click install.

Async Streams

Async streams were added in C# 8.0, allowing async methods to return multiple results. This broadens their usability, enabling async methods to return data as it becomes available. The async stream (producer method) uses a yield return statement. This returns the result to the caller and then continues to execute the method, allowing the method to make asynchronous calls in between yielding each result.
using System.Collections.Generic;
using System.Threading.Tasks;
static async IAsyncEnumerable<int> MyStream(int count)
{
  int sum = 0;
  for (int i = 0; i <= count; i++)
  {
    sum = sum + i;
    yield return sum; // return a result
    // Simulate waiting for more data
    await Task.Delay(1000);
  }
  // end stream
}
For the purpose of async streams, C# 8.0 added asynchronous versions of the generic enumerator interfaces. The IAsyncEnumerable<T> interface is used here for returning a stream that can be consumed using an await foreach loop. This variant of the foreach loop was also introduced with C# 8.0.
static async Task Main()
{
  await foreach (int data in MyStream(3))
  {
    System.Console.Write(data + " "); // "0 1 3 6"
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.210.91