C# Optimization

Apply low-level optimizations to speed up C# programs. Tune program performance.

Optimization. For an octopus, survival depends on escape. It optimizes to avoid being eaten. A C# program too can be optimized for performance, to work better and faster.

Benchmark. We must take measurements. Use Stopwatch and your mission will become easier. Keep track of the numbers in a text file (the octopus lacks this advantage).BenchmarkBenchmark: memory hierarchyBenchmark: ProfileOptimizationBenchmark: use Stopwatch

Methods. Now consider your methods. Once your figure out the important ones, begin to apply optimizations. Attack excess allocations first. The ocean is deep and dangerous.Methods: fast returnMethods: reduce call depthMethods: reduce method sizeMethods: reduce parametersMethods: reduce recursionMethods: reduce variable usageMethods: reorder parametersMethods: return multiple values fastMethods: store field in variableMethods: use AggressiveInliningMethods: use asyncMethods: use const valuesMethods: use pasted inline codeMethods: use precomputed bit countsMethods: view IL

List optimizations. The List is a beautiful thing. But if you use it foolishly, your program ends up in bad shape. A predator (like a shark) may eat it before it finishes.Lists: avoid lookupsLists: count fastLists: prefer for-loopLists: remove fastLists: use capacityLists: use Clear

Dictionary optimizations. A giant squid signals danger. In a similar way the Dictionary signals a program that is fast. Use a dictionary if lookups are needed.Dictionary: avoid loopsDictionary: change add orderDictionary: increase memoryDictionary: measure memoryDictionary: reduce dataDictionary: shorten keysDictionary: test before addingDictionary: use array if possibleDictionary: use IEqualityComparerDictionary: use memoizationDictionary: use StringComparerDictionary: use TryGetValue

Memory optimizations. Memory is a physical thing. It has shape and size (like an atom). In our performance quest we should conserve memory—use as little as possible.Memory: locality of referenceMemory: measure class sizeMemory: temporal localityMemory: use arraysMemory: use bit masksMemory: use BitArray

Array optimizations. Arrays store elements in a fast way. As the octopus hides, it could store its location in a compact array. This would help it escape faster.Array: cacheArray: count fastArray: flatten 2D arrayArray: use Buffer.BlockCopyArray: use byte arrayArray: use jagged arrayArray: use lookup tableArray: use sentinel elementArray: use separate arrays

String optimizations. Strings are immutable. Often we must create new strings as a program runs. These excess allocations are slow. We remove them if possible.Strings: avoid ReplaceStrings: avoid ToUpper, ToLowerStrings: combine format stringsStrings: fast for-loopStrings: fast int parseStrings: lowercase characters fastStrings: memory sizeStrings: path optimizationStrings: split on charsStrings: ToString int optimizationStrings: use lastIndexOfStrings: use short strings

Regex optimizations. In the deepest part of the ocean, we find regular expressions. But even Regex can be optimized. Often we optimize a Regex by removing it.Regex: optimizeRegex: prefer string loopRegex: use Compiled

StringBuilder optimizations. The StringBuilder is like a List. It grows as needed. After each operation, no allocation happens—and this speeds up programs.StringBuilder: append rangesStringBuilder: consider stringsStringBuilder: data typesStringBuilder: fast int appendStringBuilder: reduce appendsStringBuilder: store data efficientlyStringBuilder: use cacheStringBuilder: use capacityStringBuilder: use Equals

Class optimizations. Prefer classes to structs. When we pass a class to a method, only a reference is copied. With classes we avoid moving things in memory.Classes: avoid structsClasses: cache DateTimeClasses: cache typeofClasses: use static fieldsClasses: use structsClasses: use treeClasses: use Tuple

Branch optimizations. For survival the octopus does not spend its time evaluating slow logic. It moves quickly. For C# we speed up our branches with switches or for-loops.Statements: avoid LINQStatements: avoid yieldStatements: hoist try, catchStatements: reorder ifStatements: unwinding, jamming, decrementStatements: use complex expressionsStatements: use switch

Some research. You can find many optimization tips in Code Complete. I recommend this book for some tips. Some strategies may not be useful in C#. Many are still relevant.
Quote: Use a high-quality design. Make the program right. Make it modular and easily modifiable so that it's easy to work on later.
Quote: When it's complete and correct, check the performance. If the program lumbers, make it fast and small. Don't optimize until you know you need to (Code Complete).

A final note. As an octopus, hiding on the ocean floor is something to optimize for. In C# programs, optimizations to reduce allocations and reduce logical tests are more effective.

© 2007-2020 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.