Threads are also crazy - - - asynchronous programming

Keywords: C# Programming Database socket network

Preface

This section mainly introduces the basic knowledge of Task, Async and Await in asynchronous programming.

What is asynchrony?

Instead of blocking the current thread to wait for processing to complete, asynchronous processing allows subsequent operations until other threads have completed processing and callbacks notify the thread.

Asynchronous and multithreading

Similarities: Avoid calling thread blocking, thereby improving the responsiveness of the software.

Difference:

Asynchronous operations do not require additional thread burdens and are handled by callbacks. In well-designed cases, processing functions can reduce deadlock by eliminating shared variables (at least reducing the number of shared variables even if they are not completely used). The use of keywords Async and Await after C_5.0.NET 4.5 makes asynchronous programming extremely simple.

Processors in multithreading are still executed sequentially, but the disadvantages of multithreading are also obvious. The use (abuse) of threads will impose additional burden on context switching. And shared variables between threads may cause deadlocks.

Asynchronous application scenarios and principles

Asynchronism is mainly used in IO operation, database access, disk operation, Socket access, HTTP/TCP network communication.

Reasons: IO operations do not require too much CPU calculation. These data are mainly processed by disk. If synchronous communication can not be completed, more thread resources need to be created. Frequent switching of thread data context is also a waste of resources. For IO operations, there is no need to allocate a separate thread to process.

Examples are given to illustrate:

Operation: The server receives HTTP requests to operate on the database and then returns

Synchronization:

asynchronous

task

Before using tasks, the static method QueueUserWorkItem provided by thread pool is mostly used for thread invocation, but this function has many limitations. The biggest problem is that there is no internal mechanism to let developers know when the operation is completed, and there is no mechanism to get the return value when the operation is completed. To solve this problem, Microsoft introduced a task outline. Read.

First, construct a Task < TResult > object and pass the return value to TResult. After starting the task, wait for it and return the result. Sample code:

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("Start computing");
 4            // ThreadPool.QueueUserWorkItem(Sum, 10);
 5             Task<int> task = new Task<int>(Sum, 100);
 6             task.Start();
 7             //Display waiting to get results
 8             task.Wait();
 9             //call Result Waiting for the return result
10             Console.WriteLine("The result of the program is Sum = {0}",task.Result);
11             Console.WriteLine("Program end");
12             Console.ReadLine();
13         }
14 
15         public static int Sum(object i)
16         {
17             var sum = 0;
18             for (var j = 0; j <= (int) i; j++)
19             {
20                 Console.Write("{0} + ",sum);
21                 sum += j;
22             }
23             Console.WriteLine( " = {0}",sum);
24             return sum;
25         }

In addition to waiting for a single task, task also provides waiting for multiple tasks, WaitAny and WaitAll, which prevent calling threads until all Task objects in the array are completed.

Cancel tasks

Task cancellation also uses the standard cancellation mode of the. NET Framework. First, you need to create a Cancellation TokenSource object, then add the parameter Cancellation Token to the function, pass the Token of Cancellation TokenSource to the method, and then call IsCancellation Requested to get whether the value has been cancelled for judgment.

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("Start computing");
 4             // ThreadPool.QueueUserWorkItem(Sum, 10);
 5             var  ctx = new CancellationTokenSource();
 6             var task = new Task<int>(() => Sum(ctx.Token, 100000));
 7             task.Start();
 8             //Display waiting to get results
 9             //task.Wait(ctx.Token);
10             Thread.Sleep(1000);
11             ctx.Cancel();
12             //call Result Waiting for the return result
13             Console.WriteLine("The result of the program is Sum = {0}", task.Result);
14             Console.WriteLine("Program end");
15             Console.ReadLine();
16         }
17 
18         public static int Sum(CancellationToken cts, object i)
19         {
20             var sum = 0;        
21             for (var j = 0; j <= (int)i; j++)
22             {
23                 if (cts.IsCancellationRequested) return sum;
24                 Thread.Sleep(50);
25                 Console.Write("{0} + ", sum);
26                 sum += j;
27             }
28             Console.WriteLine(" = {0}", sum);
29             return sum;
30         }

Automatically start a new task after completion of the task

In practical development applications, it often happens that one task starts another task immediately after completion, and it can't block the thread. Calling result when the task is not completed will block the program and can't see the progress of the task. TASK provides a method, ContinueWith, which will not block any threads. When the first task is completed, it will start the second task immediately. .

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("Start computing");
 4             // ThreadPool.QueueUserWorkItem(Sum, 10);
 5             var  ctx = new CancellationTokenSource();
 6             var task = new Task<int>(() => Sum(ctx.Token, 100000));
 7             task.Start();
 8             var cwt = task.ContinueWith(p =>
 9             {
10                 Console.WriteLine("task result ={0} ",task.Result);
11             });
12             //Display waiting to get results
13             //task.Wait(ctx.Token);
14             Thread.Sleep(1000);
15             ctx.Cancel();
16             //call Result Waiting for the return result
17             Console.WriteLine("The result of the program is Sum = {0}", task.Result);
18             Console.WriteLine("Program end");
19             Console.ReadLine();
20         }
21 
22         public static int Sum(CancellationToken cts, object i)
23         {
24             var sum = 0;        
25             for (var j = 0; j <= (int)i; j++)
26             {
27                 if (cts.IsCancellationRequested) return sum;
28                 Thread.Sleep(50);
29                 Console.Write("{0} + ", sum);
30                 sum += j;
31             }
32             Console.WriteLine(" = {0}", sum);
33             return sum;
34         }

Async & Await is easy to use

The main purpose of using Async & Await is to facilitate asynchronous operation, because. net 4.0 used to be more complex when doing asynchronous operation, mainly by calling the asynchronous callback method provided by Microsoft to program. If you encounter a method that needs to be implemented by yourself, it is very headache. Each version of. net has its own technology, such as the delegation in. NET 1.1, the generic type in. NET 2.0, etc. Linq in 3.0, Dynimac in. NET 4.0 and asynchronous programming in. NET 4.5 are the main thrust of asynchronous programming. You only need to understand TASK + asynchronous functions to achieve asynchronous programming.

async: Tell CLR that this is an asynchronous function.

await: Asynchronously process the function of Task < TResult > return value.

 

Example purpose: Get the JS code of the website and display it in the interface.

 1  private static async Task<string> DownloadStringWithRetries(string uri)
 2         {
 3             using (var client = new HttpClient())
 4             {
 5                 // Wait 1 second before the first retry, 2 seconds for the second, and 4 seconds for the third retry.
 6                 var nextDelay = TimeSpan.FromSeconds(1);
 7                 for (int i = 0; i != 3; ++i)
 8                 {
 9                     try
10                     {
11                         return await client.GetStringAsync(uri);
12                     }
13                     catch
14                     {
15                     }
16                     await Task.Delay(nextDelay);
17                     nextDelay = nextDelay + nextDelay;
18                 }
19                 // Last retry to let the caller know the error message.
20                 return await client.GetStringAsync(uri);
21             }
22         }
 1  static  void Main(string[] args)
 2         {
 3             Console.WriteLine("Obtaining Baidu Data");
 4             ExecuteAsync();
 5             Console.WriteLine("Thread end");
 6             Console.ReadLine();
 7         }
 8 
 9         public static async void ExecuteAsync()
10         {
11            string text = await DownloadStringWithRetries("http://wwww.baidu.com");
12            Console.WriteLine(text);
13         }

Running results show that first get Baidu data, the thread ends, and finally display the JS code. This is because asynchronous opening of new threads does not cause thread blocking.

 

Posted by mikelmao on Thu, 21 Mar 2019 23:57:53 -0700