While enjoying the benefits of release, we should also be cautious that release may introduce some inexplicable bugs and releasebugs to you.

Source: Internet
Author: User

While enjoying the benefits of release, we should also be cautious that release may introduce some inexplicable bugs and releasebugs to you.

We usually use the release version when releasing a project, because the release will optimize our il code at the jit layer, such as improving the performance of iteration and memory operations, not much nonsense,

I will first use a simple "Bubble Sorting" to experience the performance gap between release and debug.

 

I. Highlights of release [Bubble Sorting]

This is an example of Bubble Sorting in the algorithm series I wrote many years ago. I will show it at will, and I am going to add 50000 pieces of data, so that I can execute 2.5 billion iterations, said Wang Jianlin, not too large

Crazy, billions of dollars is not a small value for me.

1 namespace ConsoleApplication4 2 {3 class Program 4 {5 static void Main (string [] args) 6 {7 var rand = new Random (); 8 List <int> list = new List <int> (); 9 10 for (int I = 0; I <50000; I ++) 11 {12 list. add (rand. next (); 13} 14 15 var watch = Stopwatch. startNew (); 16 17 try18 {19 BubbleSort (list); 20} 21 catch (Exception ex) 22 {23 Console. writeLine (ex. message); 24} 25 26 watch. stop (); 27 28 Console. wr IteLine ("Time consumed: {0}", watch. elapsed); 29} 30 31 // Bubble Sorting Algorithm 32 static List <int> BubbleSort (List <int> list) 33 {34 int temp; 35 // The first loop: indicates the number of times to be compared, such as list. count. You must compare count-1 times to 36 for (int I = 0; I <list. count-1; I ++) 37 {38 // list. count-1: Take the last number subscript of the data, 39 // j> I: The subscript from the back to the back must be greater than the subscript from the back to the back, otherwise it will surpass. 40 for (int j = list. count-1; j> I; j --) 41 {42 // if the previous number is greater than the next one, the 43 if (list [j-1]> list [j]) is exchanged. 44 {45 temp = list [j-1]; 46 list [j-1] = list [j]; 47 list [j] = temp; 48} 49} 50} 51 return list; 52} 53} 54}

Execution efficiency under Debug:

 

The execution efficiency below Release:

From the above two figures, we can see that the performance difference between the debug and release versions can be nearly 4 times different... It is still quite shocking.

 

Ii. Bugs that should be paid attention to in release

Release is indeed a very good thing, but do not forget to enjoy the benefits, any optimization will have to pay the price, this world will not let you take up anything good, release sometimes

Performance improvement will boldly optimize your code and cpu commands, for example, caching some of your variables and parameters in the high-speed cache of the cpu. Otherwise, how much can your performance be improved ~~~

In most cases, you will not encounter any problems, but sometimes it is unfortunate that a major problem may occur when you come out. The following is an example for your demonstration:

1 class Program 2 {3 static void Main (string [] args) 4 {5 var isStop = false; 6 7 var task = Task. factory. startNew () => 8 {9 var isSuccess = false; 10 11 while (! IsStop) 12 {13 isSuccess =! IsSuccess; 14} 15}); 16 17 Thread. sleep (1000); 18 isStop = true; 19 task. wait (); 20 21 Console. writeLine ("the main thread execution ends! "); 22 Console. ReadLine (); 23} 24}

 

The above code is very simple, so I won't bother to explain it to you, but the interesting thing is that the execution results of this code in the debug and release environments are quite different, and our routine

The idea is that after 1 ms, the main thread executes console. writeline (...), right, but the truth is: normal debug output, but release gets stuck for a long time .... Wait all the time .... This is a big

Bug... If you don't believe it, you can take a look at the following...

 

Debug:

 

Release:

 

Iii. Problem Prediction

As mentioned earlier, the release version will optimize the il code on the jit layer, so the il code of the application cannot be seen, but what you can probably guess is, or jit directly put the code

1 while (!isStop)2 {3       isSuccess = !isSuccess;4  }

Optimized

1 while (true)2 {3      isSuccess = !isSuccess;4 }

 

To speed up the execution, mainthread and task load the isStop variable from memory to their respective cpu caches. When the main thread executes isStop = true, the task reads the cpu

The dirty data in the cache, that is, the execution is based on isStop = false.

 

4. Three Solutions

1: volatile

How can this problem be solved? The first thing you think of is the volatile keyword, which I think everyone knows has two meanings:

<1> tell the compiler that jit does not optimize the cpu in any form. Thank you.

<2>. The variable must be read from memory instead of the cpu cache.

Therefore, you can optimize the Code as follows to solve the problem perfectly:

1 class Program 2 {3 volatile static bool isStop = false; 4 5 static void Main (string [] args) 6 {7 var task = Task. factory. startNew () => 8 {9 var isSuccess = false; 10 11 while (! IsStop) 12 {13 isSuccess =! IsSuccess; 14} 15}); 16 17 Thread. sleep (1000); 18 isStop = true; 19 task. wait (); 20 21 Console. writeLine ("the main thread execution ends! "); 22 Console. ReadLine (); 23} 24}

 

 

2: Thread. VolatileRead

This method is also a method added later by. net. Its function is to tell CLR that I need to read data from memory, rather than in the cpu cache. If you do not believe it, you can read the comments.

1 // 2 // Summary: 3 // read the field value. Regardless of the number of processors or the status of the processor cache, this value is the latest value written by any processor of the computer. 4 // 5 // parameter: 6 // address: 7 // the field to be read. 8 // 9 // return result: 10 // The latest value of the field written by any processor. 11 public static byte VolatileRead (ref byte address );

 

But unfortunately, there is no bool type parameter for this hanging hair, only int type... Run, in order to test, you can only change isStop to the int States 0, 1...

1 class Program 2 {3 static void Main (string [] args) 4 {5 int isStop = 0; 6 7 var task = Task. factory. startNew () => 8 {9 var isSuccess = false; 10 11 while (isStop! = 1) 12 {13 // each cycle reads the latest value of "isStop" from the memory 14 Thread. VolatileRead (ref isStop); 15 16 isSuccess =! IsSuccess; 17} 18}); 19 20 Thread. sleep (1000); 21 isStop = 1; 22 task. wait (); 23 24 Console. writeLine ("the main thread execution ends! "); 25 Console. ReadLine (); 26} 27}

3: Thread. MemoryBarrier

As a matter of fact, the explanation of this method on MSDN seems to be puzzling and incomprehensible at all.

1 // 2 // Summary: 3 // synchronize memory access as follows: the processor executing the current thread cannot execute System first when re-sorting the commands. threading. thread. memoryBarrier4 // memory access after calling, and then execute System. threading. thread. memoryBarrier calls the previous memory access method. 5 [SecuritySafeCritical] 6 public static void MemoryBarrier ();

In fact, this sentence has two meanings:

 

<1>. optimized the sorting of cpu commands.

<2> after MemoryBarrier is called, all variable writes before MemoryBarrier must be updated from cache to memory.

After MemoryBarrier is called, all variables after MemroyBarrier are read from memory instead of the cpu cache.

 

So based on the above two policies, we can use Thread. MemoryBarrier for transformation. The Code is as follows:

1 class Program 2 {3 static void Main (string [] args) 4 {5 bool isStop = false; 6 7 var task = Task. factory. startNew () => 8 {9 var isSuccess = false; 10 11 while (! IsStop) 12 {13 Thread. MemoryBarrier (); 14 isSuccess =! IsSuccess; 15} 16}); 17 18 Thread. sleep (1000); 19 isStop = true; 20 task. wait (); 21 22 Console. writeLine ("the main thread execution ends! "); 23 Console. ReadLine (); 24} 25}

In a multi-threaded environment, reading and writing a shared variable by multiple threads is a very dangerous operation. I think everyone understands the reason. At this time, you can use the above three methods to solve the problem.

... Well, I will talk about it here, hoping to help you.

 

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.