Home Articles Details

AspNet Core Performance Tuning and Best Practices (C-Sharp 10 Enhancements)


C# Best Practices and Performance Tuning

  1. Avoid Cache Misses: This is when the CPU tries to fetch data from the L1 Layer of the Memory and that layer does not have the data, it has to fetch from the L2 Layer of Memory. This is costly when It comes to performance.

    - The way you avoid this is by structuring your Repository by utilizing Arrays.

    - *1 source: Pro .Net Memory Management by Konrad Kokosa page 968

  2. [NB]: The kind of data structure you use in the application matters when it comes to performance.
               Load the data from the Database into a Data structure and all Operations e.g. #UI ajax queries should query from the Data structure /lookups.

    - Always Sort your lists so that the BranchPredictor in CPU Core can predict when a for-loop and prefetch data from an L1, L2, and L3 (worst case fetch data from Memory Stick which takes a couple of nanoseconds).

  3. Three ways you could iterate through the #Collection
    collection.ForEach(a => {
    
    //ToDo
    })
    
    //Works well with Big Data Set
    Parallel.ForEach(collection, k => {
    //ToDo
    
    })
    
    //Works well with Big Data set
    collection.AsParallel().ForAll(k => {
    //ToDo
    })
    
    //Somewhat efficient way to loop through a list
    public void Loop(){
    
    foreach(var i in CollectionMarshal.AsSpan(myCollection)){
    //Do Something
    }
    }
    
    //Prefered way by using for loop since for loop is faster than for each loop
    //really fast, no memory allocation
    //This is only safe if you are not changing items in the list you are working with
    
    public void LoopBest(){
    var spane = CollectionsMarshal.AsSpan(myCollection);
    for(var i = 0; i < span.Lengthe; i++){
    var item = span[i];
    }
    }

    - *3 Source: YouTube.com by Nick Chapsis (Fastest way to iterate a List in C-Sharp)


    3. In Asp.Net Core 7, you can now loop through the Data coming from the Database Context using await foreach, see the code below:

    //Keep in mind that this will stream the data back to the UI, if the UI is stateless then it won't
    //know of any new data, you need to use Websockets or some sort.
    await foreach(var user in _context.Users.AsAsyncEnumerable()){
    
    //Do the thingy
    
    }

2. Look in C# Class Destructors, basically, it reverses the Constructor Setters and gets Properties. e.g.

var (h,t, k,c) = myNiceClassConstructor();

3. How to Deallocate Objects in a Class after Use
    - Use Structs (Value-based references "me" and "Me" are not equal)
    - Use Spans
    - Use Array Pooling
    - Never Load Data in memory you don't need, (The CPU fetches data it does not need from memory and then dumps it, garbage)
       If the CPU has a small Cache-Line, it is forced to go roundtrip to Memory to get the Data (that it does not even need).

4. CPU Operations
    - Prefetcher fetches data from Memory and Populates

5. Shorter tables Columns are faster than longer Table Columns this is because a Developer can restrict how many rows to retrieve by using a where clause.
6. Performance "How to deallocate Objects in Memory" or at least free memory up after usage
   - Make use of IDisposabled and dispose of objects in that class after usage
     - (My Own theory): Call GC to clean up regularly so objects allocated on the Stack can be collected and free up memory.
     - Use a "Using Statement" to implement IO operations, this frees up objects allocated on the Stack as well as the Heap after usage.
     - Use WeakReferences<MyClassObject> to work with Data Modals, this lets the GC know to collect that Object Allocation in memory after it has been used.
     e.g. Dictionary<int, WeakReference<MyDataModalClass>> _myDictionary = new();
     - [NB] You can allocate Memory in C# by using: private intPtr _head = Marshale.AllocGlobal(4);


 Tools to help Look into Memory Usage of an Application

   - Use DotPeek (app developed by JetBrain) to peak into Memory Usage
   -  Use Windows Built-In "Performance Monitor" to monitor Gen1, Gen2, and Gen3 Object Allocation in Memory


Deploying to Production
1. Disable Logging when possible
    - When things are going well without Errors, disable Logging to the Console as this has a major impact on the Performance of an Application.
   - Respect the Hot Path, make sure you get the User Out of the Server as soon as possible and let other processing of the User Event follow up on a
     different Compute Server. This will save you money and time. 




References and Resources to follow

- Here is a related Article https://ernestech.com/articles/details/3871

- If you are passionate about the Speed of your code, it is important that you consider, Cache/Memory
   hierarchy as you design and implement your algorithms and data structure
    - Jan Gray

-  Cache-Line is Key!! undoubtedly if you will make even a single error in data layout, you will get 100 x slower solutions! No Joke.
      - Dimtriy Vyukov







If you log in, you will be notified when someone leaves a comment.

Other users would like to know if this solution helped you.

Jack said:

Hi

Posted On: September 19, 2022 17:04:58 PM

© 2023 - ErnesTech LLC- Privacy