All I know about. Net Asynchronization

Source: Internet
Author: User
Tags apm

I believe everyone is familiar with Asynchronization. To be accurate, return immediately after method execution. A notification will be sent when the execution is complete. That is, when a task is being executed, especially when it takes a long time to process the task, if a single thread is used for operations, it will inevitably lead to interface blocking; while asynchronous mode is used, this will not happen. Unlike synchronous processing, blocking Asynchronization is actually equivalent to synchronization.

Synchronous implementation

Let's take a look at an example of synchronization:

Suppose now we need to import the content of the text file and then process the content of the file. This requires two steps. The first step is to import the text content, which is represented by function A. The second step is to process the text, which is represented by function B. Assume that A is not finished, and B cannot. In addition, because the text content is very large and it may take dozens to dozens of minutes to import, We have to prompt the user's import progress, which involves interface interaction issues. What is the effect of synchronization? First, check the running effect:

In fact, the above picture is a program I have been running for a period of time, but due to its role in the synchronous mode, the interface is blocked, resulting in a very poor user experience.

The Code is as follows:

View code

# Region Step 1: load to the memory
Private void read1_memory ()
{
If (string. isnullorempty (filename ))
{
MessageBox. Show ("the file name cannot be blank! ");
Return;
}

String result;
Long maincount = 0;
Using (streamreader sr = new streamreader (filename, encoding. Default ))
{
While (result = Sr. Readline ())! = NULL)
{
Maincount ++;

Recordlist. Add (result); // Add records to the list for storage, so that you can proceed in the next step.

Double statusresult = (double) maincount/(double) totalcount;

Lblcurrentrecords. Text = maincount. tostring ();
Lblstatus. Text = statusresult. tostring ("p ");
Pbmain. value = int32.parse (math. Floor (statusresult) * 100). tostring ());
}
}
}
# Endregion

# Region Step 2: Process Data
Private void processrecords ()
{
If (recordlist = NULL)
{
Throw new exception ("the data does not exist! ");
}

If (recordlist. Count = 0)
{
Return;
}

Int childcount = 0;
Int recordcount = recordlist. count;

For (INT I = 0; I <recordcount; I ++)
{
String thisrecord = recordlist [I];
If (string. isnullorempty (thisrecord) |! Thisrecord. Contains (","))
{
Return;
}

String [] result = thisrecord. Split (',');

Listviewitem LVI = new listviewitem (result [0]);

For (Int J = 1; j <result. length; j ++)
{
LVI. subitems. Add (result [J]);
}
Listitem. Add (LVI );

Childcount ++;
Double percentage = (double) childcount/(double) recordcount;
Pbchild. value = int32.parse (math. Floor (percentage) * 100). tostring ());
}
}
# Endregion

So how do we run it:

# Region starts Processing
Private void btnload_click (Object sender, eventargs E)
{
Gettotalrecordnum (); // get the total number of items

Readmediamemory ();
Processrecords ();
}
# Endregion

No, we run it in sequence. The most important reason for the above situation is that the interface processing and background processing are combined in the same thread. In this way, when the background processes data, the foreground UI thread cannot update the UI. To solve this problem, use Asynchronous class processing.

In. netIn programming, which modes can be implemented asynchronously?

Four asynchronous Methods

  1. Threadpool. queueuserworkitem implementation
  2. APM mode (beginxxx and endxxx appear in pairs .)
  3. EAP mode (Event-based, which means that the task is being processed or completed, and an event will be thrown)
  4. Task

In the preceding four methods. NET 2.0 is commonly used in (1), (2), (3), and in. net 4.0 supports (4), note (4) in. NET 2.0 cannot be used because it does not exist.

First, threadpool. queueuserworkitemMethod is also the simplest method.

If the system puts the tasks to be run in the thread pool, the tasks in the thread pool have the opportunity to run in parallel.

Next, APMMode

This mode is very common, and of course it is strongly recommended by Jeff Richter. I am also a fan of this model. This mode is very easy to use, that is, to put tasks that require asynchronous processing into the begin *** method, and then accept the return value of the method through the end *** method. When the begin *** and end *** tasks are executed, we can add the notification function if UI updates are involved.

When begin *** and end *** are processed, the iasyncresult object is passed. This object will carry a delegate object in begin, then restore it in end *** and get the return value.

If you need to use multiple asynchronous methods during design and want to control their running sequence, refer to manualresetevent and autoresetevent methods, they all synchronize data by setting semaphores.

Here is an example:

Suppose now we need to import the content of the text file and then process the content of the file. This requires two steps. The first step is to import the text content, which is represented by function A. The second step is to process the text, which is represented by function B. Assume that A is not finished, and B cannot. In addition, because the text content is very large and it may take dozens to dozens of minutes to import, We have to prompt the user's import progress, which involves interface interaction issues. How can we use the APM model? First, check the running effect:

The Code is as follows:

# Region typical APM processing method, using action as a delegate without any parameters or return values
Private void beginread1_memory ()
{
Action action = new action (readmediamemory );
Action. begininvoke (New asynccallback (endread1_memory), action );
}

Private void endread1_memory (iasyncresult IAR)
{
Action action = (Action) IAR. asyncstate;
Action. endinvoke (IAR );
}

Private void beginprocessrecords ()
{
Action action = new action (processrecords );
Action. begininvoke (New asynccallback (endprocessrecords), action );
}

Private void endprocessrecords (iasyncresult IAR)
{
Action action = (Action) IAR. asyncstate;
Action. endinvoke (IAR );
}
# Endregion

How do we call it:

# When region starts processing, you must use manualresetevent to set xinhaoilang for synchronization.
Private void btnload_click (Object sender, eventargs E)
{
Gettotalrecordnum (); // get the total number of items

Beginread1_memory (); // read data to the memory
Beginprocessrecords (); // process data content
}
# Endregion

In the above Code segment, the processing method of APM mode is obvious. Begin ×× and end ×× appear in pairs. This method is easy to use, so it is recommended. In addition, if sequential execution is involved, please join my previous article:Common delegation in C #

Then let's talk about EAP.Mode

This mode is also very common. To be accurate, it is to declare the delegate event in the system, and then throw the event during or after the execution is completed. The most common is WebClientDownloadStringCompletedEvent, here we will use backgroundworker to explain, although it can implement asynchronous operations. Here, we only use an operation to read a large amount of data from the text to the memory. The figure is as follows:

Here is the operation in progress:

Here is the Undo operation:

So how is it implemented? Let's start with several events registered by backgroundworker:

The first is the dowork event. Its registration method is as follows:

bgWorker.DoWork += new DoWorkEventHandler(worker_DoWork);

This is mainly used to start the task:

Private void worker_dowork (Object sender, doworkeventargs E)
{
Backgroundworker worker = sender as backgroundworker;

Readmediamemory (worker, e); // start working
}

Then there is the progresschanged event. The registration method is as follows:

         bgWorker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

The progress report is literally performed:

Private void worker_progresschanged (Object sender, progresschangedeventargs E)
{
Pbmain. value = E. progresspercentage; // report the import progress using prograssbar.
}

Finally, the task completion report is registered as follows:

 bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

Here we can capture errors and handle task cancellation:

  private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
tsInfo.Text = "Data Loading Canceled...";
}
else
{
tsInfo.Text = "Data Loading Completed...";
}
}

Of course, this component needs to transmit the current progress information to the component during function running, and during the running process, it needs to check whether the task has been canceled, to enable automatic task cancellation:

View code

# Region Step 1: load data to the memory
Private void read1_memory (backgroundworker worker, doworkeventargs E)
{

If (string. isnullorempty (filename ))
{
MessageBox. Show ("the file name cannot be blank! ");
Return;
}

String result;
Long maincount = 0;
Using (streamreader sr = new streamreader (filename, encoding. Default ))
{
While (result = Sr. Readline ())! = NULL)
{
Maincount ++;

Recordlist. Add (result); // Add records to the list for storage, so that you can proceed in the next step.

Double statusresult = (double) maincount/(double) totalcount;
Synccontext. Send (New sendorpostcallback (S) =>
{
If (worker. cancellationpending) // The user cancels the task.
{
E. Cancel = true; // The task is canceled.
}
Else
{
Lblcurrentrecords. Text = maincount. tostring ();
Lblstatus. Text = statusresult. tostring ("p ");
Int thispercentange = int32.parse (math. Floor (statusresult * 100). tostring ());
// Pbmain. value = thispercentange;
Worker. reportprogress (thispercentange); // report the current progress
Tsnotify. Text = "| current import ";
}
}), Null );

}
}
}
# Endregion

Let's talk about the use of taskImplementation Method

The task class has never been seen before 4.0. It is very simple and convenient to use. In fact, I have also referred to many articles for the task class. The following sentence is referenced in another article:

The role of a task in parallel computing is highlighted. When a task object is constructed for the first time, its status is created. When the task is started, its status changes to waitingtorun. When a task is running on a thread, its status changes to running. When the task stops running and waits for any of its subtasks, the status changes to waitingforchildrentocomplete. When the task ends completely, it enters one of the following three States: rantocompletion, canceled, or faulted. When a task <tresult> is completed, you can use the result attribute of the task <tresult> to query the task results. When a task or task <tresult> fails, you can query the exception attribute of a task to obtain the unhandled exception thrown by the task. This attribute always returns an aggresponexception object, which contains all unhandled exceptions.
To simplify the code, the task provides several read-only Boolean attributes, iscanceled, isfaulted, and iscompleted. Note: When the task is in the rantocompleted, canceled, or faulted status, iscompleted returns true. To determine whether a task is successfully completed, the simplest method is if (task. Status = taskstatus. rantocompletion ).

Of course, we still use the above examples to program and explain.

First, we need to start a task, so the task taskone = new task (read1_memory); indicates that the read1_memory function is registered as a task to run, and then the taskone is used. start (); to start the task. So how to run the second task and wait until the first task is completed? Here we need to use its continuewith method:

Task tasktwo = taskone. continuewith (Action =>{ processrecords ();});

In this way, when running, the program will start the task in order. The graph is the same as the image in APM mode, so I will not post it. The following code is used:

            Task taskOne = new Task(ReadIntoMemory);
taskOne.Start();
Task taskTwo = taskOne.ContinueWith(Action => { ProcessRecords(); });

In the <tresult> generic method of a task, the tresult type is the return value type. It carries a task with no parameters but returned values. Therefore, the input function either has a parameter with a return value, or does not have a parameter with a return value, or does not have a parameter without a return value. If a parameter has a return value, you can use the following method:

Task<int> taskOne = new Task<int>(a=>ReadIntoMemory((int)a),5);

References

You can also refer to my questions in stackoverflow for the following purpose:

Reference blog: http://hi.baidu.com/jackeyrain/blog/item/828ec3f70bfa8635730eec0a.html

Code download

Click here to download

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.