Asynchronous programming in C # from entry to depth

Source: Internet
Author: User
Tags call back sleep terminates

The concept of asynchronous programming

Multi-core CPU Hyper-Threading CPU
1. Multi-core processor (CPU) refers to a single processor (CPU) containing multiple processing units, each processing unit it is equivalent to a one-core processor (CPU). As a result, the Multi-Core processor functions are equivalent to multiple single core processor computer online warfare.
2. Hyper-Threading Processor (CPU) refers to a CPU, using a virtual method to simulate a physical core into multiple cores (typically a single physical core, modeled as two cores, also known as the second-line path). Hyper-Threading can be called only if the number of threads is greater than the number of physical cores. such as quad-core four threads are not hyper-threading, and quad-core eight threads can be called Hyper-Threading.
3. Advantages and Disadvantages:
1 The core is the real physical core, a core of the processor (CPU), the equivalent of multiple single core processor (CPU) to collaborate with each other. Therefore, in theory, multiple cores have higher computational power than hyper-Threading. Although multiple cores operate much faster than hyper-threading, there is a clear drawback to multiple cores, which is that multiple cores are less efficient than Hyper-threading processors (CPUs). Because, many cores in processing the data, they mutually "cooperates" is not very perfect, often a core needs to wait for other core computation data, thus delays the time, is forced to sabotage. In addition, because the current multiple core is the use of shared level three cache, which makes the CPU operation of many cores slow down a lot.
2 Hyper-Threading is a virtual approach to a physical core virtual into a number of core, it can maximize the use of existing core resources, with high cost performance.
optimization of multi-core processor by operating system
Mainly reflected in the scheduling and interruption:
1. Optimize the assignment of the task. Make the same application task as much as possible on the same core.
2. Optimize shared data for tasks. Because the multi-core processor (Chip multi-processor,cmp) architecture shares a level two cache (currently), you can consider changing the data distribution of tasks in memory so that the task increases the hit rate of level two cache as much as possible during execution.
3. Load balancing optimization for tasks. When tasks are scheduled, there is a load imbalance, consider migrating tasks that are least relevant to other tasks in the busier processor to minimize data conflicts.
Processes and Threads
1. The process process is an instance of an application that consists of a private virtual address space, code, data, and various other system resources, the resources created by the process during the run are destroyed as the process terminates, and the system resources used are released or closed when the process terminates.
2. Thread threads are an execution unit within a process. After the system has created the process, it actually starts the main execution thread that executed the process. The main execution thread terminates and the process terminates.
Each thread maintains exception handlers, scheduling priorities, and thread contexts. (The thread context in which the currently executing thread is suspended at the end of its time slice and another thread continues to run.) When the system switches from one thread to another, it saves the thread context of the preempted thread and reloads the saved thread context of the next thread in the thread queue
3. The relational operating system uses processes to separate the different applications that they are executing, and the. NET Framework further subdivides the operating system process into a lightweight managed subprocess of the System.AppDomain (application domain).
A thread is a dispatch unit of a CPU, an executing unit in a process in which multiple threads can execute code at the same time.


For example, you need to have a large number of data to be stored, you do not want to side of the storage side waiting for return results, you can use asynchronous, large data into a queue, and then another thread to operate this queue inside the data warehousing, into the end, to inform the main thread. Your main thread can do anything during this time.

When we handle some long line calls, often causes the interface to stop responding or the IIS thread takes up too many issues, this time we need more asynchronous programming to fix these problems, but usually it is easier said than done, it is true that asynchronous programming is a completely different programming idea than synchronous programming. , for the developers accustomed to synchronous programming, in the development process is more difficult, controllability is not strong is its characteristics.

In. NET Framework5.0 species, Microsoft has a new language feature for us, let's use asynchronous programming as close and simple as using synchronous programming, and this article will explain some of the limitations of the previous version of the framework based on the callback ethics asynchronous programming model and the new API if we can simply do the same development task.

Why to asynchronous

All along, the use of remote resources programming is a confusing problem, different from "local resources", remote resources access will always have a lot of unexpected situations, network environment unstable machine server failure, will cause a lot of programmers completely uncontrollable problems, So this requires that programmers need more to protect remote resource calls, management calls cancellation, supermarkets, thread waiting, and processing threads for a long time did not respond to the situation. And in. NET, we often ignore these challenges, in fact we will have a variety of unused patterns to deal with asynchronous programming, such as in the processing of IO-intensive operations or high latency operations without testing the thread, most of the cases we have synchronous and asynchronous two methods to do this thing. The problem is that the current patterns are very easy to cause confusion and code errors, or developers will give up and then use blocking to develop.

And in today's. NET, it provides a programming experience that is very close to synchronous programming, and does not require a developer to deal with many of the situations that only occur in asynchronous programming, and the asynchronous invocation will be clear and opaque, combined with easy and synchronized code.

a bad experience in the past

The best way to understand this problem is our most common scenario: the user interface has only one thread all of the work is running on this thread, and the client program cannot react to the user's mouse time, most likely because the application is being blocked by a time-consuming operation, This may be because the thread is waiting for a network ID or is doing a CPU-intensive calculation, when the user interface does not get run time and the program is in a busy state, which is a very poor user experience.

For many years, the solution to this problem is to do the invocation of the asynchronous flower, not wait for the response, return the request as soon as possible, so that other events can be executed at the same time, only when the request has the final feedback to the application so that the client code can execute the specified code.

The problem is that the asynchronous code completely destroys the code flow, and the callback agent explains how it works later, but how does it wait in a while loop? An If statement? A try block or a using block? How do you explain "what to do next"?

Look at one of the following examples:

public int sumpagesizes (ilist<uri> URIs)
{
int total = 0;
foreach (Var uri in URIs)
{
Txtstatus.text = string. Format ("Found {0} bytes ...", total);
var data = new WebClient (). Downloaddata (URI);
Total + + data. Length;
}
Txtstatus.text = string. Format ("Found {0} bytes Total", total);
return total;
}

This method downloads files from a URI list, statistics their size and update state information at the same time, obviously this method does not belong to the UI thread because it takes a long time to complete, so it will completely suspend the UI, but we also want the UI to be continuously updated, how to do?

We can create a background program that continues to send data to the UI thread to get the UI to update itself, which seems wasteful because the thread spends most of the time waiting and downloading, but sometimes that's exactly what we need to do. In this example, WebClient provides an asynchronous version of the Downloaddata method-downloaddataasync, which returns immediately and then triggers an event after downloaddatacompleted, This allows the user to write an asynchronous version of the method to split what is to be done, call back immediately and complete the call on the next UI thread, thus no longer blocking the UI thread. Here is the first attempt:

public void Sumpagesizesasync (ilist<uri> URIs)
{
Sumpagesizesasynchelper (URIs. GetEnumerator (), 0);
}

public void Sumpagesizesasynchelper (ienumerator<uri> enumerator, int total)
{
if (enumerator. MoveNext ())
{
Txtstatus.text = string. Format ("Found {0} bytes ...", total);
var client = new WebClient ();
Client. downloaddatacompleted + = (sender,e) =>{
Sumpagesizesasynchelper (Enumerator, total + e.result.length);
};
Client. DownloadDataAsync (Enumerator. Current);
}
Else
{
Txtstatus.text = string. Format ("Found {0} bytes Total", total);
}
}

And then it was still bad, we broke a neat foreach loop and got a enumerator manually, each of which created an event callback. The code replaces the loop with recursion, which you should not be able to look straight at. Don't worry, it's not finished yet.

The original code returns a total and displays it, and the new one is returned to the caller before the statistics have been completed. How can we get a result to return to the caller, the answer is: The caller must support a fallback, we can call it after the statistics are complete.

But what about the anomaly? The original code does not pay attention to the exception, it will always pass to the caller, in the asynchronous version, we must extend back to allow the exception to propagate, when the exception occurs, we have to explicitly let it propagate.

Ultimately, these needs will further confuse the code:

public void Sumpagesizesasync (ilist<uri> uris,action<int,exception> callback)
{
Sumpagesizesasynchelper (URIs. GetEnumerator (), 0, callback);
}

public void Sumpagesizesasynchelper (ienumerator<uri> enumerator, int total,action<int,exception> Callback
{
Try
{
if (enumerator. MoveNext ())
{
Txtstatus.text = string. Format ("Found {0} bytes ...", total);
var client = new WebClient ();
Client. downloaddatacompleted + = (sender, E) =>
{
Sumpagesizesasynchelper (Enumerator, total + e.result.length,callback);
};
Client. DownloadDataAsync (Enumerator. Current);
}
Else
{
Txtstatus.text = string. Format ("Found {0} bytes Total", total);
Enumerator. Dispose ();
Callback (total, null);
}

}
catch (Exception ex)
{
Enumerator. Dispose ();
Callback (0, ex);
}

}

When you look at the code again, can you tell exactly what the JB thing is?

I'm afraid not, we're just going to start by trying to replace the blocking call with an asynchronous call, wrap it in a foreach loop, and think about trying to combine more asynchronous calls or more complex control structures. It's not a subpagesizesasync scale that can be solved.

Our real problem is that we can no longer explain the logic in these methods, and our code is completely out of the loop. Much of the work in asynchronous code makes the whole thing look hard to read and seems to be full of bugs.


a new way

Now that we have a new feature to solve the problem, the asynchronous version of the code will look like this:

Public async task<int> Sumpagesizesasync (ilist<uri> URIs)
{
int total = 0;
foreach (Var uri in URIs)
{
Txtstatus.text = string. Format ("Found {0} bytes ...", total);
var data = await new WebClient (). Downloaddatataskasync (URI);
Total + + data. Length;
}
Txtstatus.text = string. Format ("Found {0} bytes Total", total);
return total;
}

In addition to the highlighted section, the code above is very similar to the synchronized version of the code, the process of the code has never changed, we do not see any callbacks, but this does not mean that there is no actual callback operation, the compiler will take care of this work, no longer need you to concern.

The asynchronous approach is to use task<int> instead of the previously returned int type, and task and task<t> are provided in today's framework to represent a running job.

There is no additional method for asynchronous methods, and in accordance with the Convention, we add async as the new method name after the method name in order to distinguish the synchronized version. The method above is also asynchronous, which means that the method is treated differently by the compiler, allowing part of it to become a callback and automatically creating task<int> as the return type.

Explanation of this method: Within the method, call another asynchronous method Downloaddatataskasync, it quickly returns a task<byte[]> type of variable, it will be activated after the download data is completed, until the data has not been completed before , we don't want to do anything, so we use await to wait for the operation to complete.

It seems that the await keyword blocks threads until the task completes the downloaded data, but instead it flags the task's callback and returns immediately, which executes the callback when the task completes.


Tasks

Task and task<t> types already exist in the. NET Framework 4.0, a task represents an ongoing activity, it may be a CPU-intensive work or an IO operation running in a separate thread, It is also very easy to manually create a task that does not work on a separate thread:

Static Task Readfileasync (string filepath,out byte[] buffer)
{
Stream stream = File.Open (FilePath, FileMode.Open);
Buffer = new Byte[stream. Length];
var TCS = new taskcompletionsource<double> ();
Stream. BeginRead (buffer, 0, buffer. Length, arr =>
{
var length = stream. EndRead (arr);
Tcs. Setresult (stream. Length);
}, NULL);
Return TCS. Task;
}



Once you have created a TaskCompletionSource object, you can return the task object associated with it and ask the client code to get the final result when the relevant work is done, when the task does not occupy its own thread.

If the actual task fails, task samples can carry exceptions and propagate up, and if using await triggers the exception of the client code:

static async void Readassignedfile ()
{
byte[] buffer;
Try
{
Double length = await Readfileasync ("SomeFileDoNotExisted.txt", out buffer);
}
catch (Exception ex)
{
Console.WriteLine (ex. message);
}
}

Static task<double> Readfileasync (string filepath,out byte[] buffer)
{
Stream stream = File.Open (FilePath, FileMode.Open);
Buffer = new Byte[stream. Length];
var TCS = new taskcompletionsource<double> ();
Stream. BeginRead (buffer, 0, buffer. Length, arr =>
{
Try
{
var length = stream. EndRead (arr);
Tcs. Setresult (stream. Length);
}
catch (IOException ex)
{
Tcs. SetException (ex);
}
}, NULL);
Return TCS. Task;
}

task-based asynchronous programming model

As explained above, the asynchronous method should look like-task-based Asynchronous Pattern (TAP), the asynchronous embodiment above requires only one calling method and asynchronous asynchronous method, which returns a Task or task<t>.

Some of the conventions in tap are described below, including how to deal with "Cancel" and "in-progress", and we will further explain the task-based programming model.

Async and await

It is very important to understand that the Async method does not run on its own thread, in fact, to write a async method but without any await, it will be a de facto synchronization method:

Static async task<int> Tentosevenasync ()
{
Thread.Sleep (10000);
return 7;
}

If you call this method, it will block the thread and return 7 after 10 seconds, which may not be what you expect, and you will get a warning in VS, as this may never be the desired result.

When only one async method runs to a await statement, it immediately returns control to the caller, but only when the waiting task completes does it actually return the result, which means you need to make sure that the code in the Async method does not do too many tasks or block performance calls. The following example is the effect you expect

Static async task<int> Tentosevenasync ()
{
Await Task.delay (3000);
return 7;
}

Task.delay is actually an asynchronous version of the Tread,sleep, which returns a task that will be completed within the specified time.

time handlers and asynchronous methods with no return value

Asynchronous methods can be created using await from other asynchronous methods, but where does the asynchronous end?

In the client program, the usual answer is that the asynchronous method is initiated by the event, the user clicks a button, an asynchronous method is activated until it completes, and the event itself does not relate to when the method executes. This is what is usually called "after the hair is forgotten."

To accommodate this pattern, asynchronous methods are often explicitly designed to be "both forgotten"-using void as the return value instead of the task<tresult> type, so that the method can be used directly as an event handler. When a void Saync method executes, no task is returned and the caller cannot trace whether the call is complete or not.

Private async void Somebutton_click (object sender, RoutedEventArgs e)
{
somebutton.isenabled = false;
Await Sumpagesizesasync (Geturls ()));
Somebutton.isenabled = true;
}

End of this tutorial

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.