157 recommendations for writing high-quality code to improve C # programs--Recommendation 83: Beware of traps in parallel

Source: Internet
Author: User

Recommendation 83: Beware of traps in parallel

Parallel's for and foreach methods also support some relatively complex applications. In these applications, it allows us to perform some initialization operations at the start of each task, perform some follow-up work at the end of each task, and also allow us to monitor the status of the task. However, it is a mistake to remember that the phrase "allow us to monitor the status of a task" is wrong: the "task" should be changed to "thread". This is where the trap lies.

We need to have a deep understanding of these specific operations and applications, otherwise it is very likely to fall into this trap. Here's what the output of this piece of code looks like:

Static voidMain (string[] args) {      int[] Nums =New int[] {1,2,3,4 }; intTotal =0; Parallel.For<int> (0, Nums. Length, () =        {              return 1; }, (I, loopstate, subtotal)={Subtotal+=Nums[i]; returnsubtotal; }, (x)= Interlocked.add (refTotal , x)); Console.WriteLine ("total={0}", total);  Console.readkey (); } 


This code is likely to output 11, less case output 12, although it is theoretically possible to output 13 and 14, but we should have little chance to observe. To understand why this output is available, you must first understand the various parameters of the For method in detail. The declaration of the For method above is as follows:

 Public Static Parallelloopresult for<tlocal> (intint toexclusive, func<tlocal> localInit, func< int, parallelloopstate, tlocal, tlocal> body, action<tlocal> localfinally);

The first two parameters are relatively easy to understand, starting and ending indexes, respectively.

The body of the parameter is also relatively easy to understand, that is, the task body itself. Where subtotal is the return value of a single task.

Localinit and localfinally are more difficult to understand, and traps are here. To understand these two parameters, you must first understand the mode of operation of the Parallel.For method. The For method uses concurrency to initiate each task in the loop body, which means that the task is assigned to the thread pool to manage. In the above code, the number of loops totals 4 times, and the actual run-time scheduler starts with only one or two background threads. This is the advantage of concurrency, is also the advantage of the thread pool, parallel through the internal scheduling algorithm, to maximize the savings of thread consumption. The role of Localinit is that if parallel a new thread for us, it will perform some initialization tasks in the example above:

() =    {          return1;      

It initializes the value of subtotal in the task body to 1.

The localfinally function is that at the end of each thread, it does some finishing work:

(x) = Interlocked.add (ref

What this line of code represents is actually:

The x, in fact, represents the return value in the task body, specifically in this case, the value of subtotal on return. Using interlocked is an atomic operation on total to avoid problems caused by concurrency.

Now, we should understand why the output of the above code is uncertain. Parallel a total of 4 tasks, but we are not sure how many threads the parallel actually started for us, which is determined by the runtime based on its own scheduling algorithm. If all concurrent tasks use only one thread, the output is 11, and if two threads are used, the output is 12 according to the logic of the program.

In this code, if you let Localinit return a value of 0, you might never notice the trap:

() =    {          return0;      

Now, to understand this trap more clearly, let's use this better-understood code:

Static voidMain (string[] args) {      string[] Stringarr =New string[] {"AA","BB","cc","DD","ee","FF",          "GG","hh" }; stringresult =string.      Empty; Parallel.For<string> (0, Stringarr.length, () ="-", (i, Loopstate, Subresult)=        {              returnSubresult + =Stringarr[i]; }, (threadendstring)={result+=threadendstring; Console.WriteLine ("Inner:"+threadendstring);      });      Console.WriteLine (result);  Console.readkey (); } 

One possible output of this code is:
Inner:-aaccddeeffgghh
Inner:-bb
-aaccddeeffgghh-bb




Turn from: 157 recommendations for writing high-quality code to improve C # programs Minjia

157 recommendations for writing high-quality code to improve C # programs--Recommendation 83: Beware of traps in parallel

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.