Hi everyone! Today I want to share with you some .Net 5 performance tips with benchmarking!
I will provide benchmarks results in percentages where 100% is fastest result.
As you probably know, strings are immutable. So whenever you concatenate strings, a new string object is allocated, populated with content, and eventually garbage collected. All of that is expensive and that’s why StringBuilder will always have better performance.
.NET provides a lot of collections like List, Dictionary, and HashSet. All those collections have dynamic size capacity. They automatically expand their size as you add more items.
When the collection reaches its size limit, it will allocate a new larger memory buffer (usually an array double in size). That means an additional allocation and deallocation.
Allocation of arrays and the inevitable de-allocation can be quite costly. Performing these allocations in high frequency will cause GC pressure and hurt performance. An elegant solution is the System.Buffers.ArrayPool class found in the Systems.Buffers NuGet.
The idea is pretty similar to to the ThreadPool. A shared buffer for arrays is allocated, which you can reuse without actually allocating and de-allocating memory. The basic usage is by calling ArrayPool.Shared.Rent(size). This returns a regular array, which you can use any way you please. When finished, call ArrayPool.Shared.Return(array) to return the buffer back to the shared pool.
Structs have several benefits when it comes to deallocation:
The StackAlloc keyword in C## allows for very fast allocation and deallocation of unmanaged memory. That is, classes won’t work, but primitives, structs, and arrays are supported.
Never use ConcurrentBag without benchmarking. This collection has been designed for very specific use-cases (when most of the time an item is dequeued by the thread that enqueued it) and suffers from important performance issues if used otherwise. If in need of a concurrent collection, prefer ConcurrentQueue.
#c-sharp #programming #.net #csharp