Chapter 06 of asynchronous programming series asynchronous mode (TAP) based on tasks, Chapter 06 tap
Preface
At the school of Asynchronization, a garden friend recommended async in C #5.0, and did not find the Chinese version. I also happen to want to improve the English version. I translated some important parts in poor English, which is purely entertaining, simple sharing, keep learning, and remember to be modest.
If you think the translation is meaningless, please step on it. If you think it is encouraging, thank you for your praise. May the garden friends who love technology leave it alone in the future. Every time you think independently, do not choose to follow the stream, or do your best, and do not do what you do, and do not live up to the meaning of each second.
For reprinting and crawlers, please refer to the original article link http://www.cnblogs.com/tdws/p/5679001.html. The bokepark snail bait will be available on August 1, June 27, 2016.
Directory
Chapter 2 Introduction to asynchronous programming
Chapter 2 Why asynchronous programming
Chapter 2 manual asynchronous code writing
Chapter 4 compile the Async Method
Chapter 4 What does Await do?
Chapter 1 asynchronous mode based on tasks
Chapter 1 tools for asynchronous code
Chapter 2 which thread is running your code
Chapter 2 exceptions in asynchronous programming
Chapter 2 Concurrent Use of asynchronous programming
Chapter 4 unit test your asynchronous code
Chapter 2 asynchronous programming in ASP. NET Applications
Chapter 2 asynchronous programming in WinRT applications
Chapter 2 what does the compiler do for your Asynchronization at the underlying layer?
Chapter 1 Performance of asynchronous code
Task-based asynchronous mode
The Task-based asynchronous programming mode (TAP) is Microsoft. net platform using the Task programming provided by a formation and documentation-address (TRANSLATOR: will also translate this document, write really good): http://www.microsoft.com/en-gb/download/details.aspx? Id = 19957. Stephen Toub from Microsoft's parallel programming team provides a good example in the document, which is worth reading.
This mode provides an APIs that can be consumed (called) by await. When the async keyword is used to write a method that complies with this mode, handwriting tasks are usually useful. In this chapter, I will introduce how to use this mode and technology.
What does TAP mean?
I suppose we already know how to use C # To design a good Asynchronous Method:
· It should have as few parameters as possible, or even no parameters. If possible, avoid the ref and out parameters.
· If it makes sense, he should have a return type, which can truly express the result of the method code, rather than the successful mark like C ++.
· It should have a name that can interpret its own behavior without additional symbols or comments.
Expected errors should be part of the return type, rather than unexpected errors should be thrown.
Here is a well-designed Asynchronous Method under the DNS class:
public static IPHostEntry GetHostEntry(string hostNameOrAddress)
TAP provides the same principles for designing asynchronous methods based on the Asynchronous Method skills you have mastered. As follows:
· It should have the same parameters as the asynchronous method, and the ref and out parameters must be avoided.
· He should return the Task or Task <T>. Of course, it depends on whether your method has a return type. This task should be completed at a certain time in the future and provide results.
· It should be named NameAsync. Name is equivalent to the Name of the asynchronous method you represent.
· Exceptions caused by errors (unexpected) during method running should be thrown directly. Any other exceptions (as expected) should be thrown out by the Task.
Below is a good design of the TAP method:
public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress)
All of this seems obvious, but as we have mentioned earlier, there are several methods of. NET asynchronous programming.
The key concept of TAP is to return tasks asynchronously, which encapsulates the results of time-consuming operations in the future. Without this idea, we used to add additional parameters to the method, or add additional methods or events to support the callback mechanism. Tasks can contain the basic content required by any callback, without the clutter of previous details to pollute your method, resulting in difficulties in reading and writing.
The additional advantage is that because the asynchronous callback mechanism is currently in the Task, you do not need to copy and prepare the callback method everywhere during asynchronous calls. This, in turn, means that this mechanism can take on more complex and powerful tasks, so that it can do something feasible like restoring context, including synchronizing context. It also provides a common API for processing asynchronous operations, so that the compiler functions are as reasonable as async, and other modes cannot achieve this effect.
Use tasks for computing-intensive operations
Sometimes, a time-consuming operation does not require network requests or access to the disk; it only takes time for a complex operation that requires a lot of processing time. Of course, we cannot expect to do this without occupying threads like network requests. However, on the UI of the program, we still want to avoid the non-response caused by the UI freezing. To solve this problem, we have to return the UI thread to process other events and use a different thread for time-consuming computing.
Task provides a very simple method to do this, and you can use await to update the UI after computing is complete, just like other asynchronous methods. (Note: Task. run () can start a new background thread .)
Task t = Task.Run(() => MyLongComputation(a, b));
The Task. Run method uses a thread in the ThreadPool to execute your delegate. In this case, I use lambda to make it easier to pass local variables to the computation. The resulting Task starts immediately, and we can await this Task:
await Task.Run(() => MyLongComputation(a, b));
This is a simple way to work with backend threads.
For example, you need more control, such as which thread is used to execute computing or how to queue. Task has a static property called TaskFactory. It has a StratNew method to control the execution of your computation:
Task t = Task.Factory.StartNew(() => MyLongComputation(a, b),cancellationToken,TaskCreationOptions.LongRunning,taskScheduler);
If you are writing a class library containing a large number of computing-intensive methods, you may have neglected h to provide an asynchronous version for your method, that is, you can call the Task. run to start working in the background thread version. This is not a good idea, because your API callers are more familiar with the thread requirements of applications than you do. For example. In web applications, using a thread pool is not advantageous; the only thing that should be optimized is the total number of threads. Task. Run is a simple call, so if necessary, leave the API for the caller to call.
Create a controllable Task
The TAP is really easy to consume (called), so you can easily provide the TAP mode in all your interfaces. We already know how to do this when consuming other TAP APIs, and how to use Asynchronous methods. But what if there is no available tap api for time-consuming operations? Maybe this is an API that uses other asynchronous modes. Maybe you are not consuming (calling) an API but doing some completely manual asynchronous operations.
The tool we use here is TaskCompletionSource <T>, which is a method for creating tasks under your control. You can make the Task complete at any time you want, or you can give it an exception anywhere to make it fail.
Let's take a look at this example. Suppose you want to encapsulate a prompt in the following method:
Task<bool> GetUserPermission()
This encapsulates a custom dialog box prompting the user to agree. Because user permission is required in many places in your program, it is very important to define a method that is easy to call. This is a great place to use the asynchronous method, because you must release the UI thread to display the dialog box. However, it is not similar to the traditional Asynchronous Method for network requests and other time-consuming operations. Here, we are waiting for users. Let's take a look at the interior of this method.
private Task<bool> GetUserPermission(){ // Make a TaskCompletionSource so we can return a puppet Task TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); // Create the dialog ready PermissionDialog dialog = new PermissionDialog(); // When the user is finished with the dialog, complete the Task using SetResult dialog.Closed += delegate { tcs.SetResult(dialog.PermissionGranted); }; // Show the dialog dialog.Show(); // Return the puppet Task, which isn't completed yet return tcs.Task;}
Note that this method is not marked as async; we manually create a Task, so we do not want the compiler to create a Task for us. TaskCompletionSource <T> creates a Task and returns it as an attribute. We can use the SetResult method to complete the Task on TaskCompletionSource.
Since we comply with the TAP, our callers can use await to wait for the user's permission. This call is natural.
if (await GetUserPermission()){ ...
One headache is that TaskCompletionSource <T> does not have any non-generic version. However, because the Task <T> is the parent class of the Task, you can use the Task <T> wherever you need the Task. In turn, it means that you can use a TaskCompletionSource <T> and the Task <T> returned by a Task as the attribute is completely valid. I often use a TaskCompletionSource <Object> and call SetResult (null) to complete it. You can easily create a non-generic TaskCompletionSource. If you need it, you can create a non-generic TaskCompletionSource based on a generic type ).
Interaction with the old asynchronous mode
The. NET team created a version of the TAP mode on all important asynchronous programming APIs of the framework. But it is interesting to understand how to build a non-TAP asynchronous code into a TAP. In this case, you need to interact with existing asynchronous code. The following is an interesting example of how to use TaskCompletionSource <T>.
Let's check the method of using the DNS example. In. NET4.0, the asynchronous version used by this DNS method is the IAsyncResult mode. This means that it includes the Begin method and the End method:
IAsyncResult BeginGetHostEntry(string hostNameOrAddress,AsyncCallback requestCallback,object stateObject)IPHostEntry EndGetHostEntry(IAsyncResult asyncResult)
In general, you may consume (CALL) this API by using a lambda as the callback, and in it we want to call the End method. We need to make it clear here that the value uses a TaskCompletionSource <T> to complete a Task.
public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress){ TaskCompletionSource<IPHostEntry> tcs = new TaskCompletionSource<IPHostEntry>(); Dns.BeginGetHostEntry(hostNameOrAddress, asyncResult => { try { IPHostEntry result = Dns.EndGetHostEntry(asyncResult); tcs.SetResult(result); } catch (Exception e) { tcs.SetException(e); } }, null); return tcs.Task;}
This code is more complicated by possible exceptions. If this DNS method fails, an exception is thrown when we call the EndGetHostEntry method. This is why the IAsyncResult mode uses a more confusing System in the End method than simply passing the result to the callback method. When an exception is thrown, we should load it into our TaskCompletionSource <T> so that our callers can get the exception in the form of TAP.
In fact, we have enough APIs to follow this pattern. For example, the. NET Framework Team has compiled a tool method to convert them into the TAP version, as shown below:
Task t = Task<IPHostEntry>.Factory.FromAsync<string>(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null);
It uses the Begin and End methods as the delegate, and uses a similar mechanism as before. But it may be more efficient than our simple method.
Cold Task and hot Task
In. in NET4.0, the parallel job library is initially converted to the Task type. It has the concept of cold Task, which still needs to be started. The corresponding hot Task is already running. So far, we have only processed hot tasks.
The TAP clearly indicates that all tasks must be hot before returning from the method. Fortunately, the tasks created in all the technologies we mentioned earlier are hot tasks. The exception is TaskCompletionSource <T>, which does not actually have the concept of cold or hot Task. Make sure that the Task can be completed at a certain time in the future.
Preliminary work
We already know that when you call the Asynchronous Method of a TAP, this method runs in the current thread like any other method. The difference is that the TAP method does not actually complete the work before returning. It returns a Task immediately, and the Task will be completed after the actual work is completed.
As we have already said, some code will run synchronously in the method and in the current thread. In this case, the Asynchronous Method is at least code reachable and includes the operands. The first await, as we mentioned in "Asynchronous Method is synchronized until it is needed.
We recommend that you use the TAP method to minimize the number of synchronization tasks. You can check whether the parameter is valid, or scan a cache to avoid time-consuming operations, and you should not perform a slow calculation in it. A hybrid method is a good method to perform some operations and then perform some network requests or similar things. However, you should use Task. Run to move the calculation to the background thread. Imagine the conventional function of uploading images to a website, but you must first adjust the size to save the bandwidth:
Image resized = await Task.Run(() => ResizeImage(originalImage));await UploadImage(resized);
This is very important in the UI app, which has no special benefits for web apps. When we see a method that follows the TAP mode, we want it to return quickly. Anyone who uses your code and moves it to the UI app will be a "surprise" If your picture adjustment is very slow"
Conclusion
Updates this week are slow. If you need an original English document, you can send a private message or leave a message. If any error occurs, you may want to point it out. The next article will introduce some tools and methods for asynchronous code.