For loop optimization

Hi guys, I am writing C # code that currently should run as fast as possible, usually taking up one core with 100% for about 25 minutes. I need the code to remain a single core, since the advantage of running this code in multiple cores will not be as big as running this project several times at once

This code is as follows

public Double UpdateStuff(){ ClassA[] CAArray = ClassA[*a very large number indeed*]; Double Value = 0; int length = CAArray.Length; for (int i= 0; i< length ; i++) { Value += CAArray[i].ClassB.Value * CAArray[i].Multiplier; } return Value; } 

This area of ​​code is responsible for 78% of the application load in accordance with the profilers and, thus, is a good candidate for optimization.

!!! Note: the function has been changed from the return type to void to return a Double type, this is pseudocode, not the actual code, to make reading easier

To Clarify: .net, C # 4.0, visual studio 2010, target machine: Windows 2008 x64 server

Edit: further clarification: all variables in this context are publicly available, not properties. The values ​​in CAArray [i] .ClassB.Value will forever change if the pairs do not match.

+4
source share
11 answers

You must remove this:

 int length = CAArray.Length; 

and replace the loop as follows:

 for (int i= 0; i < CAArray.Length; i++) { Value += CAArray[i].ClassB.Value * CAArray[i].Multiplier; } 

Saving length, like your source code, actually slows down C # code (intuitive, I know). This is because if you have Array.Length directly in the for loop, the jitter will skip checking the bounds of the array at each iteration of the loop.

In addition, I highly recommend parallelizing this process. The easiest way to do this is

 CAArray.AsParallel().Sum(i => i.ClassB.Value * i.Multiplier); 

although you can get even more speed without LINQ (although then you need to worry about the details of the low level of multi-thread control).

+10
source

Try:

 for (int i = 0; i < length; i++) { var a = CAArray[i]; Value += a.ClassB.Value * a.Multiplier; } 
+6
source

One difference is the use of a temporary variable inside the for loop to hold the current value.

The second difference, perhaps more importantly, is that CAArray.Length instead of count takes into account the for-loop border. The compiler optimizes such a loop to eliminate border checks.

 for (int i = 0; i < CAArray.Length; i++) { var curr = CAArray[i]; Value += curr.ClassB.Value * curr.Multiplier; } 

Another thing you can do is make the ClassB, ClassB.Value and Multiplier properties as fields, if you can.

Last - do not forget to check the "Optimize code" in the solution properties so that the compiler can optimize your code.

+6
source

Another micro optimization that can affect performance on very large sets defines field instead of property .

 for (int i= 0; i< length ; i++) { var a = CAArray[i]; Value += a.ClassB.value_field * a.multiplier_field; } 

Even if the use of properties is recommended from MS, it is well known that properties introduce very small (but may be important for very large data) overhead.

Hope this helps.

+3
source

If you have a lot of duplication by factor and ClassB.Value , you may need to find all the individual pairs, multiply each pair once and then multiply by the number of occurrences of that pair.

In addition, I would go for AsParallel() and use all the cores.

+1
source

I don’t know how much control you have over ClassA , but it seems to me that since Multiplier and ClassB are properties of ClassA , you have to modify ClassA to have this computed value property. Theoretically, you already have all these classes created with the corresponding properties already set, and therefore you can easily calculate the desired value of this.ClassB.Value * this.Multiplier when setting up ClassB.Value or Multiplier . This way you reduce the cost of this cycle and instead move it to instantiate your data. Is this a worthy compromise? You will need to learn more about what is happening in your application, but this will reduce the load on this particular function. Subsequently, all you have to do is:

 public void UpdateStuff(){ ClassA[] CAArray = ClassA[*a very large number indeed*]; Double Value = 0; int length = CAArray.Length; for (int i= 0; i< length ; i++) { Value += CAArray[i].MultipliedClassBValue; } return Value; } 

plus any further improvements that wonderful people might have.

+1
source

Another minor improvement would be to use preincrement for the index, because postincrement should return the value that the iterator had before it increased; so the previous value needs to be copied somewhere before changing it with the appropriate increment so that it is available for return.

The extra work can be a little or a lot, but it, of course, cannot be less than zero, compared with a preincrement, which can simply perform an increment, and then return the value just changed - without copying // saving // etc.

0
source
  • Parallelize it.
  • Try to expand the loop. (The compiler can do this on its own.)
0
source

Another thing to be careful is if you often allocate really large arrays (86K + of data), and the size is different every time you can call GC too much, because these objects are allocated on LOH.

0
source

Since the array has a huge number of elements, something like this will be faster than other loop iteration methods.

 try { for (int i= 0; ; i++) { var a = CAArray[i]; Value += a.ClassB.value_field * a.multiplier_field; } } catch (IndexOutOfRangeException) { } 

Although, admittedly, it looks pretty ugly and is definitely not a β€œclean” way of programming. But at the same time, using open fields instead of properties is also not clean.

In addition to benefiting from the removal of the exit condition, a curious bug in CLR 2.0 for X86 makes the for loop faster if it is enclosed in a try catch as Jitter, in which case it prefers to use registers on the processor stack to store local residents.

0
source

First of all, it is emptiness, so it should not return anything (or should return Double). Secondly, C # usually does not use Egyptian curly braces, but that does not make any difference.

Then you can try using Linq and lambdas, I think it can be faster - cleaner at least!

 public void UpdateStuff() { ClassA[] CAArray = new ClassA[large_number]; Double Value = CAArray.Select(x => x.ClassB.Value * x.Multiplier).Sum(); } 
-3
source

All Articles