1. Evolution
Key records of this document. The different implementation schemes of asynchronous programming in different periods under net platform. Asynchronous programming on the net platform has undergone several evolutions:
- Asynchronous Programming Model(APM): This mode is also known as IAsyncResult mode, in. Net1. It was proposed at 0:00 that asynchronous operations can be achieved in synchronous methods by calling methods starting with BeginXXXX and EndXXXX. This mode requires allocation and recycling of IAsyncResult objects to reduce resource consumption and does not support the ability to cancel and provide progress reports. Microsoft does not recommend this mode.
- Event-based Asynchronous Pattern(EAP): It is an asynchronous implementation based on an event pattern, in. Net2. Proposed at 0:00, this pattern has one or more Async-suffixed methods and Completed events that support cancellation, progress reporting, and reporting results of asynchronous methods, and is based on APM mode, which is efficient but. Not all classes are supported in net, and it is difficult to control when the business is complex, which Microsoft does not recommend.
- Task-based Asynchronous Pattern(TAP:task): It is an asynchronous implementation based on task mode, which is implemented in. Net4. As suggested at 0, there are four ways to create Task, 1. Task. Factory. StartNew()2. (new Task (()=>{//TODO})). Start()3. Task. Run() is. net4.5 increase 4.Task.FromResult(), recommended by Microsoft.
- Task-based Asynchronous Pattern(TAP:async/await): It is an asynchronous implementation based on task mode, which is implemented in. net4.5. It was suggested that it is essentially equal to the third implementation. Using these two keywords would make the code look comparable and concise to synchronous code, further removing the complex structure of asynchronous programming, which Microsoft strongly recommends.
2. Mode: APM and EAP
2.1. APM
I used APM mode to invoke services most extensively during WCF. Now APM mode is seldom used except UI interaction. The following example only shows APM encoding mode
1 public void Test(){ 2 var urlStr="http://www.test.com/test/testAPM"; 3 var request=HttpWebRequest.Create(url); 4 request.BeginGetResponse(AsyncCallbackImpl,request);//Initiate Asynchronous Request 5 } 6 public void AsyncCallbackImpl(IAsyncResult ar){ 7 var request=ar.AsyncState as HttpWebRequest; 8 var response=request.EndGetResponse(ar);//End asynchronous request 9 using(var stream=response.GetResponseStream()){ 10 var sbuilder=new StringBuilder(); 11 sbuilder.AppendLine($"Current Thread Id:{Thread.CurrentThread.ManagedThreadId}"); 12 var reader=new StreamReader(stream); 13 sbuilder.AppendLine(reader.ReadLine()); 14 Console.WriteLine(sbuilder.ToString()); 15 } 16 }
2.2. EAP
Used in most database connection drivers, I've used them in instant messaging software, and the following example only shows the EAP encoding pattern
2.2.1. Demo: WebClient
1 public void Test(){ 2 var wc=new WebClient(); 3 wc.DownloadStringCompleted+=wc_DownloadStringCompleted; 4 wc.DownloadStringAsync(new Uri("http://www.test.com/test/testEAP")); 5 } 6 public void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e){ 7 Console.WriteLine(e.Result); 8 }
2.2.2. Demo: BackgroundWorker
1 public void Test(){ 2 var bgworker=new BackgroundWorker(); 3 bgworker.DoWork+=bgworker_DoWork; 4 bgworker.RunWorkerCompleted+=bgworker_RunWorkerCompleted; 5 bgworker.RunWorkerAsync(null);//Parameters are passed to DoWork In the event subscriber method, the internal BeginInvoke()Method 6 } 7 public void bgworker_DoWorker(object sender,DoWorkEventArgs e){ 8 Console.WriteLine("dowork"); 9 } 10 public void bgworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){ 11 Console.WriteLine("dowork completed"); 12 }
3. Mode: TAP
3.1. Common Objects and Methods
Since Microsoft recommends TAP encoding, this section is the focus of this article. In fact, TAP mainly uses the following objects and methods to achieve asynchronous programming:
1) Task <Result>: Asynchronous Task
2) Task <Result>. ContinueWith (Action): Continues a task, specifying an action to continue after the task has been executed
3) Task.Run(): Create an asynchronous task
4) Task.WhenAll(): Return to Task when all incoming tasks are completed
5) Task.WhenAny(): Returns to Task when one of the incoming tasks is completed
6) Task.Delay(): Asynchronous delayed wait, example Task.Delay(2000).Wait()
7) Task.Yield(): After entering an asynchronous method, if there is time-consuming synchronous code before await and you want this part of the code to execute asynchronously, you can add await Task in the first line after entering an asynchronous method. Yield() code because it forces the current method to be executed asynchronously.
3.2. Keywords: async/await
1) The method marked with the async keyword becomes an asynchronous method, which usually contains one or more instances of the await keyword. If the await keyword is not used to identify the object method in the asynchronous method, the asynchronous method is considered a synchronous method.
2) The await keyword cannot wait for an asynchronous method with a void return type, and the caller of the void return method cannot catch any exceptions thrown by the asynchronous method.
3) Asynchronous methods cannot declare in, ref, or out parameters, but they can call methods that contain such parameters.
3.3. Use examples
3.3.1. Synchronization method
1 public void Test(){ 2 Console.WriteLine($"Header executed, current main thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 3 var result = SayHi("abc"); 4 Console.WriteLine(result); 5 Console.WriteLine($"Tail Executed, Current Main Thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 6 Console.ReadKey(); 7 } 8 public string SayHi(string name){ 9 Task.Delay(2000).Wait();//Asynchronous Wait 2 s 10 Console.WriteLine($"SayHi Execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 11 return $"Hello,{name}"; 12 }
3.3.2. Asynchronous implementation
1 public void Test(){ 2 Console.WriteLine($"Header executed, current main thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 3 var result = SayHiAsync("abc").Result; 4 Console.WriteLine(result); 5 Console.WriteLine($"Tail Executed, Current Main Thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 6 Console.ReadKey(); 7 } 8 public Task<string> SayHiAsync(string name){ 9 return Task.Run<string>(() => { return SayHi(name); }); 10 } 11 public string SayHi(string name){ 12 Task.Delay(2000).Wait();//Asynchronous Wait 2 s 13 Console.WriteLine($"SayHi Execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 14 return $"Hello,{name}"; 15 }
3.3.3. Continuation of tasks
1 public void Test(){ 2 Console.WriteLine($"Header executed, current main thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 3 var task = SayHiAsync("abc"); 4 task.ContinueWith(t=>{ 5 Console.WriteLine($"Continue Execution, Current Thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 6 var result=t.Result; 7 Console.WriteLine(result); 8 }); 9 Console.WriteLine($"Tail Executed, Current Main Thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 10 Console.ReadKey(); 11 } 12 public Task<string> SayHiAsync(string name){ 13 return Task.Run<string>(() => { return SayHi(name); }); 14 } 15 public string SayHi(string name){ 16 Task.Delay(2000).Wait();//Asynchronous Wait 2 s 17 Console.WriteLine($"SayHi Execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 18 return $"Hello,{name}"; 19 }
3.3.4. async/await refactoring
1 public void Test(){ 2 Console.WriteLine($"Header executed, current main thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 3 SayHiKeyPair("abc"); 4 Console.WriteLine($"Tail Executed, Current Main Thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 5 Console.ReadKey(); 6 } 7 public async void SayHiKeyPair(string name){ 8 Console.WriteLine($"Asynchronous call header execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 9 var result = await SayHiAsync(name); 10 Console.WriteLine($"Asynchronous call tail execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 11 Console.WriteLine(result); 12 } 13 public Task<string> SayHiAsync(string name){ 14 return Task.Run<string>(() => { return SayHi(name); }); 15 } 16 public string SayHi(string name){ 17 Task.Delay(2000).Wait();//Asynchronous Wait 2 s 18 Console.WriteLine($"SayHi Execution, current thread Id For:{Thread.CurrentThread.ManagedThreadId}"); 19 return $"Hello,{name}"; 20 }
3.4. Run the process
To avoid cluttering concepts, a simple overview is that the XXXXAsync method returns a Task <Result>, await Task <Result> waiting for asynchronous results, among which some logic unrelated to asynchronous tasks can be executed.
4. To: TAP
4.1. APM to TAP
Now turn the APM implementation in Section 2 into a TAP implementation, mainly with Task.Factory.FromAsync method
1 public void APMtoTAP(){ 2 var urlStr="http://www.test.com/test/testAPM"; 3 var request=HttpWebRequest.Create(url); 4 Task.Factory.FromAsync<HttpWebResponse>(request.BeginGetResponse,request.EndGetResponse,null,TaskCreationOptions.None) 5 .ContinueWith(t=>{ 6 var response=null; 7 try{ 8 response=t.Result; 9 using(var stream=response.GetResponseStream()){ 10 var sbuilder=new StringBuilder(); 11 sbuilder.AppendLine($"Current Thread Id:{Thread.CurrentThread.ManagedThreadId}"); 12 var reader=new StreamReader(stream); 13 sbuilder.AppendLine(reader.ReadLine()); 14 Console.WriteLine(sbuilder.ToString()); 15 } 16 }catch(AggregateException ex){ 17 if (ex.GetBaseException() is WebException){ 18 Console.WriteLine($"An exception occurs with the following information:{ex.GetBaseException().Message}"); 19 }else{ 20 throw; 21 } 22 }finally{ 23 if(response!=null){ 24 response.Close(); 25 } 26 } 27 }); 28 }
4.2. EAP to TAP
1 public void Test(){ 2 var wc=new WebClient()// WebClient Class supports Event-based Asynchronous Mode(EAP) 3 var tcs = new TaskCompletionSource<string>();//Establish TaskCompletionSource And its underlying Task object 4 5 wc.DownloadStringCompleted+=(sender,e)=>{//One string After downloading, WebClient Objects should be sent DownloadStringCompleted Event 6 if(e.Error != null){ 7 tcs.TrySetException(e.Error);//Attempting to base Tasks.Task<TResult>Convert to Tasks.TaskStatus.Faulted state 8 }else if(e.Cancelled){ 9 tcs.TrySetCanceled();//Attempting to base Tasks.Task<TResult>Convert to Tasks.TaskStatus.Canceled state 10 }else{ 11 tcs.TrySetResult(e.Result);//Attempting to base Tasks.Task<TResult>Convert to TaskStatus.RanToCompletion Status. 12 } 13 }; 14 tsc.Task.ContinueWith(t=>{//For the following tasks GUI Execution on a thread, must be marked as TaskContinuationOptions.ExecuteSynchronously 15 if(t.IsCanceled){ 16 Console.WriteLine("The operation has been cancelled"); 17 }else if(t.IsFaulted){ 18 Console.WriteLine("An exception occurs with the following information:" + t.Exception.GetBaseException().Message); 19 }else{ 20 Console.WriteLine(String.Format("Operation completed with the following results:{0}", t.Result)); 21 } 22 },TaskContinuationOptions.ExecuteSynchronously); 23 24 wc.DownloadStringAsync(new Uri("http://www.test.com/test/testEAP")); 25 }
5. Summary
When designing asynchronous programming, you want to determine whether the asynchronous operation is I/O-Bound (also known as I/O-intensive due to I/O blocking) or CPU-Bound (also known as computation-intensive due to CPU blocking), which makes a better choice of approach. Computing intensive is not that the more tasks you have, the better. If the number of tasks exceeds the core number of CPUs, the more time you spend switching tasks, the less efficient the CPU will be. I/O intensive Since tasks are primarily on hard disk and network reads and writes, the CPU can handle many tasks.
The reason for this article is that since no similar articles have been found and only one article is needed to record as many articles as possible, it is necessary to go back to the mover and sort out the summary.
6. Reference information
- https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/#:~:text=For%20more%20information%2C%20see%20Task-based%20Asynchronous%20Pattern%20%28TAP%29.,event%20handler%20delegate%20types%2C%20and%20EventArg%20-derived%20types.
- https://www.cnblogs.com/fanfan-90/p/12006157.html
- https://www.cnblogs.com/zhili/archive/2013/05/13/TAP.html
- https://www.cnblogs.com/jonins/p/9558275.html